- ① SSH、ユーザー追加
- ② IPv4/IPv6追加、netplan、ufw
- ③ Apache2
- ④ Let's Encrypt
- ⑤ PHP
- ⑥ MariaDB
- ⑦ WordPress
- ⑧ Dovecot、Postfix
- ⑨ Vsftpd
- ⑩ Python
- ⑪ llama.cpp、ChromaDB
- ⑫ Anaconda、Keras、TensorFlow
- ⑬ Node.js
- ⑭ MongoDB
- ⑮ Mosquitto
- ⑯ RabbitMQ
- ⑰ Supervisor
01インストール
旧サーバーはLet's Encryptではなく自己署名証明書での運用だったため、④で扱ったPTR設定等は不要。
/etc/mosquitto/certs・/etc/mosquitto/ca_certificatesに証明書一式(サーバー証明書・クライアント証明書・CA証明書)をコピーし、confもパスの指定だけだったためそのまま流用できた。
02「Protocol error」との格闘
mosquitto_subでの接続確認テストで、素っ気ないError: Protocol errorのみが返る状態に。ブローカー側のログを見ると、より具体的な手がかりがあった。
まず疑ったのはシステム時刻・証明書の有効期限のズレ(海外フォーラムで見つかった、まったく同じエラー文言の実例がこのケースだった)。 確認したところ、新サーバーの時刻は正しく同期済み、証明書の有効期間(2024年発行、2034年まで)も問題なし。この線は外れた。
03気づき:client.crtもコピーされていた
証明書一式を見直すと、サーバー証明書だけでなくclient.crtもコピーされていることに気づいた。これは旧サーバーが相互TLS認証(クライアント証明書認証)を使っていた可能性を示す手がかりだった。
ただしmosquitto.confにrequire_certificateの設定は見当たらず、必須ではなさそうだった。
切り分けのため--insecure(ホスト名検証をスキップ)を付けてテストしたところ、あっさり接続に成功。原因が特定できた。
localhostで接続先ホスト名とも一致していたが、証明書にsubjectAltName(SAN)拡張が含まれていなかった。
近年のTLSライブラリはCNベースの照合を非推奨化しており、SANがないと一致していても検証に失敗する。2024年発行という証明書の古さがそのまま影響していた。
04最終的な接続確認
クライアント証明書+--insecureの組み合わせで、subscribe側にhelloが届き、双方向の疎通を確認できた。
PHPアプリ側は既に自己署名証明書向けのTLSオプション(ホスト名検証緩和に相当する設定)を入れていたため、この構成のまま問題なく動く見込み。証明書自体の作り直し(SAN付与)は必須ではなく、今回は見送った。
05PHP側(Composer)
純粋なPHPライブラリのため、⑭のMongoDBのようなPECL拡張の手間は不要だった。
06ここまでの状態
- Mosquitto本体・自己署名証明書一式を旧サーバーから移行
- 「Protocol error」の原因はSANなしの古い証明書によるホスト名検証失敗と特定
- クライアント証明書+--insecureでの疎通確認済み
- php-mqtt/clientをComposerで導入
- PHPアプリ側の実地確認(appw.jpホスト設定、DNS未切替の影響含む)は別途検証