Files
Qris-Soundbox/18-mqtt-broker-mosquitto-debian13.md
2026-06-04 11:20:16 +07:00

7.4 KiB

MQTT Broker Mosquitto on Debian 13

Panduan operasional untuk menyiapkan broker MQTT awal platform QRIS Soundbox di Debian 13 dengan subdomain broker.bizone.id.

Keputusan arsitektur terkait:

  • D-026: broker MQTT sungguhan ditunda sampai infrastruktur siap; simulator/outbox tetap dipakai selama transisi.
  • D-027: broker awal memakai Mosquitto, dengan kontrak topic dan adapter backend tetap migration-ready ke EMQX/managed MQTT.

Target Setup

  • Broker: Eclipse Mosquitto.
  • Domain: broker.bizone.id.
  • MQTT TLS publik: 8883/tcp.
  • MQTT local-only: 1883/tcp pada 127.0.0.1.
  • TLS: Let's Encrypt.
  • Auth: username/password.
  • Authorization: ACL topic per user/device.
  • Anonymous access: disabled.

DNS dan Paket

Pastikan DNS broker.bizone.id sudah mengarah ke public IP server.

dig +short broker.bizone.id
curl -4 ifconfig.me

Install paket:

sudo apt update
sudo apt install -y mosquitto mosquitto-clients certbot ufw
sudo systemctl enable --now mosquitto

Firewall

sudo ufw default deny incoming
sudo ufw default allow outgoing

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 8883/tcp

sudo ufw enable
sudo ufw status verbose

Jangan buka 1883/tcp ke internet. Listener 1883 hanya untuk localhost/internal test.

Sertifikat TLS

Ambil sertifikat Let's Encrypt:

sudo certbot certonly --standalone -d broker.bizone.id

Copy sertifikat ke lokasi yang bisa dibaca Mosquitto:

sudo install -d -o root -g mosquitto -m 750 /etc/mosquitto/certs

sudo install -o root -g mosquitto -m 640 \
  /etc/letsencrypt/live/broker.bizone.id/fullchain.pem \
  /etc/mosquitto/certs/fullchain.pem

sudo install -o root -g mosquitto -m 640 \
  /etc/letsencrypt/live/broker.bizone.id/privkey.pem \
  /etc/mosquitto/certs/privkey.pem

Buat renewal hook:

sudo nano /etc/letsencrypt/renewal-hooks/deploy/mosquitto-cert-copy.sh

Isi:

#!/usr/bin/env bash
set -euo pipefail

DOMAIN="broker.bizone.id"

install -o root -g mosquitto -m 640 \
  "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" \
  /etc/mosquitto/certs/fullchain.pem

install -o root -g mosquitto -m 640 \
  "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" \
  /etc/mosquitto/certs/privkey.pem

systemctl reload mosquitto

Aktifkan:

sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/mosquitto-cert-copy.sh

User dan Password

Buat user backend dan device test:

sudo mosquitto_passwd -c /etc/mosquitto/passwd qris-backend
sudo mosquitto_passwd /etc/mosquitto/passwd DEVICE_UUID_FROM_PLATFORM
sudo chown root:mosquitto /etc/mosquitto/passwd
sudo chmod 640 /etc/mosquitto/passwd

Rekomendasi:

  • qris-backend dipakai backend platform.
  • Username device memakai device_id UUID dari platform, supaya ACL pattern bisa mengikat topic devices/{deviceId}/... ke user/device.

ACL Topic

Buat file ACL:

sudo nano /etc/mosquitto/acl

Isi awal:

user qris-backend
topic readwrite devices/#

pattern write devices/%u/uplink/#
pattern read devices/%u/downlink/#
pattern write devices/%u/heartbeat

Permission:

sudo chown root:mosquitto /etc/mosquitto/acl
sudo chmod 640 /etc/mosquitto/acl

Konfigurasi Mosquitto

Buat file:

sudo nano /etc/mosquitto/conf.d/qris.conf

Isi minimal:

per_listener_settings true

listener 8883 0.0.0.0
protocol mqtt
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
certfile /etc/mosquitto/certs/fullchain.pem
keyfile /etc/mosquitto/certs/privkey.pem

listener 1883 127.0.0.1
protocol mqtt
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl

Catatan Debian:

  • Jangan set ulang persistence, persistence_location, log_dest, atau log_type di conf.d/qris.conf jika sudah ada di /etc/mosquitto/mosquitto.conf.
  • Jika muncul error Duplicate persistence_location value, hapus persistence dan persistence_location dari qris.conf.
  • Jika muncul error Duplicate "log_dest file" value, hapus blok logging dari qris.conf.

Test config:

sudo mosquitto -c /etc/mosquitto/mosquitto.conf -v

Jika tidak ada error, tekan Ctrl+C, lalu restart service:

sudo systemctl restart mosquitto
sudo systemctl status mosquitto --no-pager

Pastikan listener terbuka:

sudo ss -lntp | grep mosquitto

Expected:

  • 0.0.0.0:8883
  • 127.0.0.1:1883

Test Publish Subscribe

Terminal 1, subscribe sebagai backend:

mosquitto_sub \
  -h broker.bizone.id \
  -p 8883 \
  -u qris-backend \
  -P 'PASSWORD_BACKEND' \
  -t 'devices/DEVICE_UUID_FROM_PLATFORM/uplink/#' \
  -v

Terminal 2, publish sebagai device:

mosquitto_pub \
  -h broker.bizone.id \
  -p 8883 \
  -u DEVICE_UUID_FROM_PLATFORM \
  -P 'PASSWORD_DEVICE' \
  -t 'devices/DEVICE_UUID_FROM_PLATFORM/uplink/dynamic-qr/request' \
  -m '{"request_id":"test-001","amount":10000}'

Test ACL negatif:

mosquitto_pub \
  -h broker.bizone.id \
  -p 8883 \
  -u DEVICE_UUID_FROM_PLATFORM \
  -P 'PASSWORD_DEVICE' \
  -t 'devices/OTHER_DEVICE_UUID/uplink/dynamic-qr/request' \
  -m '{}'

Pesan ke topic device lain harus ditolak atau tidak sampai ke subscriber.

Monitoring

sudo journalctl -u mosquitto -f
sudo tail -f /var/log/mosquitto/mosquitto.log
sudo ss -lntp | grep mosquitto

Test renewal TLS:

sudo certbot renew --dry-run

Environment Backend Nanti

Saat adapter broker sungguhan dipasang ke platform:

MQTT_PUBLISH_MODE=broker
MQTT_BROKER_URL=mqtts://broker.bizone.id:8883
MQTT_USERNAME=qris-backend
MQTT_PASSWORD=...
MQTT_CLIENT_ID=qris-platform-backend
MQTT_CONNECT_TIMEOUT_MS=5000
MQTT_TLS=true

Topic kontrak yang harus dipertahankan:

devices/{deviceId}/uplink/dynamic-qr/request
devices/{deviceId}/downlink/dynamic-qr/response
devices/{deviceId}/downlink/payment/success
devices/{deviceId}/downlink/config/push
devices/{deviceId}/uplink/config/ack
devices/{deviceId}/heartbeat

Provisioning Credential Device

Credential MQTT device dibuat dari aplikasi, lalu password satu kali tersebut dimasukkan ke Mosquitto. Jalankan backend platform lebih dulu, lalu rotate credential:

ADMIN_TOKEN=admin-dev-token \
npm run mqtt:provision-device -- \
  --base-url http://127.0.0.1:3000 \
  --device-id DEVICE_UUID_FROM_PLATFORM

Output berisi:

  • mqtt_username: sama dengan device_id.
  • mqtt_password: secret satu kali untuk dimasukkan ke broker dan device.
  • mosquitto_commands: perintah yang bisa dijalankan di server broker.

Jika script dijalankan langsung di host broker:

ADMIN_TOKEN=admin-dev-token \
npm run mqtt:provision-device -- \
  --base-url http://127.0.0.1:3000 \
  --device-id DEVICE_UUID_FROM_PLATFORM \
  --apply-local

Setelah password dimasukkan, reload Mosquitto:

sudo systemctl reload mosquitto

Catatan penting:

  • Platform hanya menyimpan fingerprint secret, bukan plaintext password.
  • Jika password hilang, lakukan rotate ulang dan update device + broker.
  • ACL pattern bergantung pada username yang sama dengan device_id; jangan mengganti username device menjadi device_code kecuali kontrak topic/ACL ikut diubah.

Migration Ready Notes

  • Jangan mengunci business logic di fitur Mosquitto-specific.
  • Credential device tetap dikelola domain platform.
  • Topic tetap devices/{deviceId}/....
  • mqtt_messages tetap menjadi outbox/trace awal di aplikasi.
  • Benchmark sebelum milestone 20k, 50k, dan 100k connected device.