スマートフォン・タブレットからインターネットサーバーオペレーション

APPW.jp
 
ConoHa VPS移設記/2GB・3コア → 4GB・4コア/Ubuntu 26.04 LTS

⑮ Mosquitto

本体のインストール自体はシンプルだったが、旧サーバーから持ち込んだ自己署名証明書まわりで 「Protocol error」という素っ気ないエラーに何度も向き合うことになった回。 同じ症状の実例が海外フォーラムに見つかったのが突破口になった。

作業端末: iPad mini(Termius)

MIGRATION ROADMAP — 全17工程
  1. ① SSH、ユーザー追加
  2. ② IPv4/IPv6追加、netplan、ufw
  3. ③ Apache2
  4. ④ Let's Encrypt
  5. ⑤ PHP
  6. ⑥ MariaDB
  7. ⑦ WordPress
  8. ⑧ Dovecot、Postfix
  9. ⑨ Vsftpd
  10. ⑩ Python
  11. ⑪ llama.cpp、ChromaDB
  12. ⑫ Anaconda、Keras、TensorFlow
  13. ⑬ Node.js
  14. ⑭ MongoDB
  15. ⑮ Mosquitto
  16. ⑯ RabbitMQ
  17. ⑰ Supervisor

01インストール

login-user@新サーバー
$ sudo apt install mosquitto mosquitto-clients

旧サーバーはLet's Encryptではなく自己署名証明書での運用だったため、④で扱ったPTR設定等は不要。 /etc/mosquitto/certs・/etc/mosquitto/ca_certificatesに証明書一式(サーバー証明書・クライアント証明書・CA証明書)をコピーし、confもパスの指定だけだったためそのまま流用できた。

02「Protocol error」との格闘

mosquitto_subでの接続確認テストで、素っ気ないError: Protocol errorのみが返る状態に。ブローカー側のログを見ると、より具体的な手がかりがあった。

/var/log/mosquitto/mosquitto.log
OpenSSL Error[0]: error:0A000438:SSL routines::tlsv1 alert internal error Client <unknown> disconnected: Protocol error.

まず疑ったのはシステム時刻・証明書の有効期限のズレ(海外フォーラムで見つかった、まったく同じエラー文言の実例がこのケースだった)。 確認したところ、新サーバーの時刻は正しく同期済み、証明書の有効期間(2024年発行、2034年まで)も問題なし。この線は外れた。

03気づき:client.crtもコピーされていた

証明書一式を見直すと、サーバー証明書だけでなくclient.crtもコピーされていることに気づいた。これは旧サーバーが相互TLS認証(クライアント証明書認証)を使っていた可能性を示す手がかりだった。 ただしmosquitto.confにrequire_certificateの設定は見当たらず、必須ではなさそうだった。

切り分けのため--insecure(ホスト名検証をスキップ)を付けてテストしたところ、あっさり接続に成功。原因が特定できた。

根本原因:SANなしの古い自己署名証明書 証明書のCNはlocalhostで接続先ホスト名とも一致していたが、証明書にsubjectAltName(SAN)拡張が含まれていなかった。 近年のTLSライブラリはCNベースの照合を非推奨化しており、SANがないと一致していても検証に失敗する。2024年発行という証明書の古さがそのまま影響していた。

04最終的な接続確認

login-user@新サーバー(subscribe側)
$ mosquitto_sub -h localhost -p 8883 \ --cafile /etc/mosquitto/ca_certificates/ca.crt \ --cert /etc/mosquitto/certs/client.crt \ --key /etc/mosquitto/certs/client.key \ --insecure \ -t test/topic -u ユーザー名 -P パスワード
login-user@新サーバー(publish側)
$ mosquitto_pub -h localhost -p 8883 \ --cafile /etc/mosquitto/ca_certificates/ca.crt \ --cert /etc/mosquitto/certs/client.crt \ --key /etc/mosquitto/certs/client.key \ --insecure \ -t test/topic -m "hello" -u ユーザー名 -P パスワード hello

クライアント証明書+--insecureの組み合わせで、subscribe側にhelloが届き、双方向の疎通を確認できた。 PHPアプリ側は既に自己署名証明書向けのTLSオプション(ホスト名検証緩和に相当する設定)を入れていたため、この構成のまま問題なく動く見込み。証明書自体の作り直し(SAN付与)は必須ではなく、今回は見送った。

05PHP側(Composer)

login-user@新サーバー
$ composer require php-mqtt/client

純粋なPHPライブラリのため、⑭のMongoDBのようなPECL拡張の手間は不要だった。

06ここまでの状態

  • Mosquitto本体・自己署名証明書一式を旧サーバーから移行
  • 「Protocol error」の原因はSANなしの古い証明書によるホスト名検証失敗と特定
  • クライアント証明書+--insecureでの疎通確認済み
  • php-mqtt/clientをComposerで導入
  • PHPアプリ側の実地確認(appw.jpホスト設定、DNS未切替の影響含む)は別途検証
← 前回: ⑭ MongoDB 次回: ⑯ RabbitMQ →

『ConoHa VPS移設記 ⑮ Mosquitto』を公開しました。