VPS に Mosquitto をインストールしてブラウザと IoT デバイス間で双方向通信を行う (1)

MQTT Mosquitto ブラウザ Web ソケット WebSocket IoTデバイス 監視・制御 SSL/TLS

背景

MQTT プロトコルは IoT 機器の監視・制御に最適な通信方式です。 Mosquitto や EMQX社 から無料で利用できる MQTT Broker が提供されていて手軽に利用できます。 しかし予期せぬサーバーの停止により IoT 機器の監視・制御に不都合をきたしたり、相乗りサーバーのためどうしてもセキュリティに対する不安も残ります。

これらの課題を解決するために VPS サーバーにセキュリティ対策も行った MQTT Broker をインストールして IoT システムを構成しました。 特に Web ブラウザと MQTT Broker 間の MQTT over WebSockets with TLS に多くの試行錯誤をともなったので整理して記録を残します。

ゴール

図1 Web ブラウザ IoT デバイス 間 MQTT 通信

・VPS サーバーに MQTT Broker インストール
・TLS(SSL) によるセキュリティ対応
・IoT デバイス (C++) と MQTT Broker 間は MQTT over TLS (mqtts://) 通信
・Web ブラウザ (HTML, Java Script, CSS) と MQTT Broker 間 MQTT over WebSockets with TLS (wss://) 通信

本章では MQTT Broker mosquitto のインストールまでを記録します。

前提条件

・VPSサーバー Linux OS Debian (バージョン 6.1.153-1)
・IoT デバイス ESP32-DevKitC
・開発プラットフォーム Visual Studio Code (バージョン:1.105.0)
・拡張機能 PlatformIO IDE for VSCode (バージョン 3.3.4)
・開発言語 Linux , C++, HTML, Java Script, CSS
・通信プロトコル MQTT over TLS (mqtts://), MQTT over WebSockets with TLS (wss://)

事前準備

事前に必要なポートを開放しておきます。
・443 Web Server with TLS
・8883 MQTT over TLS
・8884 MQTT over WebSockets with TLS
 ( Mosquitto のデフォルトポートとは異なりますが、ここでは 8883, 8884 を使用します。)

Mosquitto インストール

(参考)【Mosquitto】MQTTブローカの構築・動作確認 (ユーザ認証・TLS暗号化まで)

インストールされているパッケージのアップデートとアップグレードを実行します。

$ sudo apt update -y
$ sudo apt upgrade -y


mosquitto と mosquitto-clients をインストールします。

$ sudo apt install -y mosquitto mosquitto-clients


mosquitto を起動して状態を確認します。

$ sudo systemctl start mosquitto
$ sudo systemctl status mosquitto


次のように active(running) が表示されていれば正常に動作しています。

● mosquitto.service – Mosquitto MQTT Broker
Loaded: loaded (/lib/systemd/system/mosquitto.service; enabled; preset: enabled)
Active: active (running) since Tue 2025-09-30 16:50:08 JST; 27s ago
Docs: man:mosquitto.conf(5)
man:mosquitto(8)
Process: 31582 ExecStartPre=/bin/mkdir -m 740 -p /var/log/mosquitto (code=exited, status=0/SUCCESS)
Process: 31583 ExecStartPre=/bin/chown mosquitto /var/log/mosquitto (code=exited, status=0/SUCCESS)
Process: 31584 ExecStartPre=/bin/mkdir -m 740 -p /run/mosquitto (code=exited, status=0/SUCCESS)
Process: 31585 ExecStartPre=/bin/chown mosquitto /run/mosquitto (code=exited, status=0/SUCCESS)
Main PID: 31586 (mosquitto)
Tasks: 1 (limit: 1105)
Memory: 1.4M
CPU: 15ms
CGroup: /system.slice/mosquitto.service
mq31586 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf

Sep 30 16:50:08 ik1-343-31522 systemd[1]: Starting mosquitto.service – Mosquitto MQTT Broker…
Sep 30 16:50:08 ik1-343-31522 systemd[1]: Started mosquitto.service – Mosquitto MQTT Broker.


サーバーの再起動時に mosquitto を自動的に起動する設定にします。

$ sudo systemctl enable mosquitto


enable コマンドを入力すると次の応答が表示されます。

Synchronizing state of mosquitto.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable mosquitto

ユーザー認証を設定する


新規にパスワードを設定する場合は次のコマンドを実行します。
 username は任意のユーザ名に変更します。

$ sudo mosquitto_passwd -c /etc/mosquitto/pwfile username

 パスワード入力とパスワードの再入力を要求されるので入力します。
 別のユーザーを入力する場合は -c オプションを省略します。

次のコマンドでハッシュ関数により生成されたファイルの内容を確認します。

$ sudo cat /etc/mosquitto/pwfile

ファイルの内容は次のようになります。

username:
$7$101$9Q431FaAwu2+qLZQ$N663LIOWArnjj+urJxAUW1tOmL/OILPw7XarwSHMmQHov+M/4hlslWx3migoOXfsCI3PZuLgnx9jkHa9Y+JhGg==

username の部分には先ほど入力した任意のユーザー名が表示されます。

Apache のインストールと SSL/TLS 証明書の取得

(参考)Debian に Apache をインストールして Let’s Encrypt で HTTPS 対応するまで

Web サーバー Apache のインストールとSSL/TLS 証明書を取得します。Apache が動作すると SSL/TLS 証明書が正しくインストールされているかを容易に確認することができます。すでにインストールされている場合はこれらの手順はスキップします。

インストールされているパッケージのアップデートを確認してアップグレードを実行します。

$ sudo apt update -y
$ sudo apt upgrade -y

Web サーバー Apache をインストールします。

$ sudo apt install -y apache2

certbot というツールを使うことで、無料で利用できる Let’s Encrypt 認証局から SSL/TLS 証明書を取得することができます。

$ sudo apt install -y certbot python3-certbot-apache

certbot の登録を行います。

$ sudo certbot register

 email address を求められるので入力します。
 Terms of Service に同意を求められるので yes を入力します。
 email adress のシェアについて聞かれるので yes または no を入力します。
 Account registered. が表示されれば登録完了です。

証明書を取得します。

$ sudo certbot

domain name(s) を求められるので入力します。
 Certificate と Key の保存場所が表示されます。
 domein-nameの部分は先ほど入力したものになります。
 certificate の有効期限が表示されていますが、自動更新タスクが設定されているので安心です。

 Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/domein-name/fullchain.pem
Key is saved at: /etc/letsencrypt/live/domein-name/privkey.pem
This certificate expires on 2025-12-28.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.



Apache を再起動します。

$ sudo systemctl restart apache2



TCP ソケットの LISTEN、ポート番号、プロセスを確認します。

$ sudo ss -tlnp | grep apache2


Apache2 が HTTP ポート 80 と HTTPS ポート 443 を LISTEN していることが分かります。

LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:((“apache2”,pid=5066,fd=3),(“apache2”,pid=5065,fd=3),(“apache2”,pid=5064,fd=3))
LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:((“apache2”,pid=5066,fd=4),(“apache2”,pid=5065,fd=4),(“apache2”,pid=5064,fd=4))

ブラウザに https://ドメイン名/index.html を入力します。


https://domain name/index.html



HTTPS 通信が正しく実行されて Apache デフォルトのページが表示されました。

Mosquitto 設定ファイルの編集


Mosquitto 設定を mqtts:// および wss:// に対応するように次のファイルを編集します。
 /etc/mosquitto/mosquitto.conf

$ sudo nano /etc/mosquitto/mosquitto.conf



パスワード認証を必須として設定します。

allow_anonymous false
password_file /etc/mosquitto/pwfile

MQTT over TLS ( mqtts:// ) 設定を行います。

ポート 8883 を使用します。

listener 8883



TLS v1.2 のみに限定してセキュリティを高めます。

tls_version tlsv1.2

Using Let’s Encrypt certificates with mosquitto に従って cafile、 certfile、 keyfile のディレクトリとファイル名を指定します。

cafile /etc/ssl/certs/ISRG_Root_X1.pem
certfile /etc/letsencrypt/live/hostname/fullchain.pem
keyfile /etc/letsencrypt/live/hostname/privkey.pem

cafile と certfile、keyfile はディレクトリが異なりますので注意が必要です。

MQTT over WebSockets with TLS ( wss:// ) 設定を行います。

ポート 8884 を使用します。

listener 8884



WebSockets プロトコルを指定します。

protocol websockets



TLS v1.2 のみに限定してセキュリティを高めます。

tls_version tlsv1.2

Using Let’s Encrypt certificates with mosquitto に従って cafile、 certfile、 keyfile のディレクトリとファイル名を指定します。

cafile /etc/ssl/certs/ISRG_Root_X1.pem
certfile /etc/letsencrypt/live/hostname/fullchain.pem
keyfile /etc/letsencrypt/live/hostname/privkey.pem

cafile と certfile、keyfile はディレクトリが異なりますので注意が必要です。

mosquitto.conf の内容をまとめて再掲します。(コメント行は非表示)

pid_file /run/mosquitto/mosquitto.pid

persistence true
persistence_location /var/lib/mosquitto/

log_dest file /var/log/mosquitto/mosquitto.log

include_dir /etc/mosquitto/conf.d

allow_anonymous false
password_file /etc/mosquitto/pwfile

listener 8883
tls_version tlsv1.2
cafile /etc/ssl/certs/ISRG_Root_X1.pem
certfile /etc/letsencrypt/live/hostname/fullchain.pem
keyfile /etc/letsencrypt/live/hostname/privkey.pem

listener 8884
protocol websockets
tls_version tlsv1.2
cafile /etc/ssl/certs/ISRG_Root_X1.pem
certfile /etc/letsencrypt/live/hostname/fullchain.pem
keyfile /etc/letsencrypt/live/hostname/privkey.pem

証明書ファイルのパーミッション変更


証明書ファイルフォルダのパーミッションがデフォルト 700 に設定されている場合は 755 に変更します。

$ sudo chmod 755 /etc/letsencrypt/live

変更後のパーミッションを確認した結果です。

drwxr-xr-x 3 root root 4096 Sep 29 20:52 live

秘密鍵のパーミッションがデフォルト 600 に設定されている場合は 644 に変更します。

$ sudo chmod 644 /etc/letsencrypt/archive/domein-name/privkey1.pem

変更後のパーミッションを確認した結果です。

-rw-r–r– 1 root root 241 Sep 29 20:52 /etc/letsencrypt/archive/domein-name/privkey1.pem

ブラウザから接続するための MQTT over WebSockets with TLS ( wss:// ) については MQTT クライアントツールとの接続はできるのですが、html、Java Scrit、css でコードを書いて Web ブラウザから mosquitto に接続しようとしても、どうしてもできず試行錯誤を繰り返しました。

他にも試行錯誤でパーミッションを変更した部分があるのですが、どの程度までが必須かは別途クリーンインストールの機会があれば検証したいと思います。

パーミッションの変更が完了したら mosquitto を再起動します。

$ sudo systemctl restart mosquitto

コマンドラインによる動作確認

mosquitto_client をインストールすると mosquitto_pub, mosquitto_sub コマンドラインを使って MQTT 双方向通信を確認することができます。 ただしこれらのコマンドは MQTT over WebSockets with TLS ( wss:// ) には対応してなさそうなので、MQTT over TLS (mqtts:// ) プロトコルでのみ確認を行います。

mosquitto_sub コマンドで Subscribe (受信)を起動します。
 -h    hostname 
 -p    port
 –cafile PEM encoded CA certificates
 -u    
username ( mosquitto_passwd 作成時のユーザー名を入力 )
 –pw  password (mosquitto_passwd 作成時のパスワードを入力 )
 -t    MQTT topic (MQTT メッセージを分類するために任意の文字列を入力 )
 -d   デバグメッセージが表示させるために -d オプションを付加
 &   バックグラウンドで実行させるためにコマンドの末尾に & を付加

$ mosquitto_sub -h “hostname” -p 8883 –cafile /etc/ssl/certs/ISRG_Root_X1.pem -u “username” –pw “password” -t “MQTT topic” -d &
[1] 239795
Client (null) sending CONNECT
Client (null) received CONNACK (0)
Client (null) sending SUBSCRIBE (Mid: 1, Topic: MQTT topic, QoS: 0, Options: 0x00)
Client (null) received SUBACK
Subscribed (mid: 1): 0

jobs コマンドでバックグラウンドの実行状況を確認します。

$ jobs
[1]+ Running mosquitto_sub -h “hostname” -p 8883 –cafile /etc/ssl/certs/ISRG_Root_X1.pem -u “user-name” –pw “19551121” -t “MQTT topic” -d &

mosquitto_pub コマンドでメッセージの Publish (送信)を行います。
 -m  message (例 {“title”:”test12345″} を JSON フォーマットで送信 )

$ mosquitto_pub -h “hostname” -p 8883 –cafile /etc/ssl/certs/ISRG_Root_X1.pem -u “username” –pw “password” -t “MQTT topic” -m “{\”title\”:\”test12345\”}” -d
Client (null) sending CONNECT
Client (null) received CONNACK (0)
Client (null) sending PUBLISH (d0, q0, r0, m1, ‘MQTT topic’, … (20 bytes))
Client (null) sending DISCONNECT
Client (null) received PUBLISH (d0, q0, r0, m0, ‘MQTT topic’, … (20 bytes))
{“title”:”test12345″}
Client (null) sending PINGREQ
Client (null) received PINGRESP
received PUBLISH の次の行に受信したメッセージ {“title”:”test12345″} が表示されています。

まとめ

mosquitto をインストールして MQTT Broker として稼働することができました。

以下の 2 点に注意する必要がありました。

  ・cafile に /etc/ssl/certs/ISRG_Root_X1.pem を使用する
  ・証明書ファイルに関連してパーミッション変更が必要

(YI)

コメント

error: Content is protected !!
タイトルとURLをコピーしました