mqtt 转发网关
128
MGW 是一个开箱即用的 MQTT 转发网关:Go 后端 + Vue 3 管理界面打包在单个容器内,通过浏览器即可维护 MQTT 连接、配置上下行主题映射、调试收发消息。
mqtt:// / mqtts://(TLS)、ClientID、账号密码、Keepalive、连接超时、最大报文、重试次数,实时展示连接状态与收发统计+ / # 通配符按位改写主题(如 iot/+/up → cloud/+/up),支持双向/单向镜像包含:
| 组件 | 说明 |
|---|---|
| Go 网关二进制 | 管理 API、MQTT 客户端、转发引擎 |
| Vue 3 前端静态资源 | Nginx 直接托管 |
| Nginx | 提供 Web 页面,并把 /api、/health 反代到容器内网关 |
| 运行时 | Alpine Linux,非 root 用户运行网关进程 |
docker run -d --name mgw \
--restart unless-stopped \
-p 26063:80 \
-e TZ=Asia/Shanghai \
-v mgw-data:/app/data \
sllwakeup/mgw:latest
打开 http://localhost:26063,首次登录账号从容器内读取:
docker exec mgw cat /app/data/initial-credentials.txt
请登录后立即在「个人信息」修改密码;修改成功后该文件会自动删除。
services:
mgw:
image: sllwakeup/mgw:latest
container_name: mgw
restart: unless-stopped
ports:
- "26063:80" # 管理界面
# - "7883:7883" # 仅在需要使用「测试设备」内嵌 broker 时开放
environment:
TZ: Asia/Shanghai
volumes:
- ./data:/app/data # 持久化数据(必须)
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s
docker compose up -d
| 容器端口 | 用途 | 是否建议映射 |
|---|---|---|
80 | 管理界面(Nginx) | ✅ 映射到宿主机任意端口,如 26063:80 |
2883 | 管理 API(只监听容器内 127.0.0.1,由 Nginx 反代) | ❌ 不需要 |
7883 | 「测试设备」内嵌 MQTT broker(仅启动测试设备时监听) | ⚠️ 按需,不要暴露到公网(无认证) |
必须把 /app/data 挂载到宿主机或命名卷,否则容器重建后数据丢失:
| 路径 | 内容 | 说明 |
|---|---|---|
/app/data/state.json | 连接、分组、调试订阅/开关 | 原子写入,权限 0600 |
/app/data/secrets.yaml | 管理端密码 hash、JWT secret | 首次启动自动生成 |
/app/data/initial-credentials.txt | 初始管理账号密码 | 改密成功后自动删除 |
/app/data/logs/ | 按天滚动的运行日志 | 可选持久化 |
备份:
docker run --rm -v mgw-data:/data -v "$PWD":/backup alpine \
tar czf /backup/mgw-backup.tar.gz -C /data .
恢复时把备份解压回同名卷/目录即可。
数据版本:
state.json当前为 v3;旧 v1/v2 数据在启动时自动迁移,无需手工处理。
镜像内置默认配置 /app/configs/config.yaml,可通过只读挂载覆盖:
# 管理 API(容器内仅监听 127.0.0.1,由 Nginx 反代;不要改成 0.0.0.0)
admin_listen_host: "127.0.0.1"
admin_listen_port: 2883
admin_username: "admin"
admin_token_ttl_seconds: 86400
# 允许跨域的管理台来源,逗号分隔(同源部署时通常不需要调整)
admin_allowed_origins: "http://localhost:26063,http://127.0.0.1:26063"
# MQTT 断线重连间隔(秒)
reconnect_interval_seconds: 5
# 优雅退出等待时间(秒)
shutdown_timeout_seconds: 10
# 日志与状态文件(相对容器工作目录 /app)
log_level: "INFO"
log_dir: "data/logs"
state_file: "data/state.json"
secrets_file: "data/secrets.yaml"
| 参数 | 含义 | 默认值 |
|---|---|---|
admin_listen_host | 管理 API 监听地址(容器内) | 127.0.0.1 |
admin_listen_port | 管理 API 端口 | 2883 |
admin_username | 管理端用户名 | admin |
admin_token_ttl_seconds | 登录 token 有效期(秒) | 86400 |
admin_allowed_origins | 允许跨域来源,逗号分隔 | http://localhost:26063,... |
reconnect_interval_seconds | MQTT 断线重连间隔(秒) | 5 |
shutdown_timeout_seconds | 优雅关闭等待(秒) | 10 |
log_level | 日志级别(DEBUG/INFO/WARN/ERROR) | INFO |
log_dir | 日志目录 | data/logs |
state_file | 业务状态文件 | data/state.json |
secrets_file | 密钥文件 | data/secrets.yaml |
| 变量 | 说明 |
|---|---|
TZ | 容器时区,例如 Asia/Shanghai;影响日志与页面时间显示(镜像已内置 tzdata) |
容器内置 HTTP 健康检查:
curl http://localhost:26063/health
# {"status":"ok"}
docker compose 已配置 healthcheck,docker ps 中状态会显示 healthy。
建议把 MGW 放在自己的 Nginx / Traefik 后面并启用 HTTPS,只暴露一个域名:
server {
listen 443 ssl;
server_name mgw.example.com;
ssl_certificate /etc/ssl/mgw.crt;
ssl_certificate_key /etc/ssl/mgw.key;
location / {
proxy_pass http://127.0.0.1:26063;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 120s;
}
}
如果通过非默认域名/端口访问,且前端与 API 不同源,请把页面来源加入
admin_allowed_origins。
配置挂载提示:只想用默认配置时不要挂载
config.yaml(尤其不要挂载一个不存在的文件——Docker 会把它创建成目录导致启动失败)。需要自定义时,先复制默认配置:docker run --rm sllwakeup/mgw:latest cat /app/configs/config.yaml > config.yaml
docker compose pull # 或 docker pull sllwakeup/mgw:latest
docker compose up -d
state.json 自动升级到最新版本/app/datadocker commit 把运行中的容器提交为镜像(会把运行数据一起固化)本地 docker build 只会产出构建机架构的镜像(例如 Apple Silicon 上是 arm64)。发布到 Docker Hub 供 x86_64 服务器使用时,请用 buildx 构建多架构:
docker login
docker buildx create --use --name mgw-builder 2>/dev/null || true
cd docker/MqttGateWay
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t sllwakeup/mgw:latest \
--push .
镜像为多阶段构建:前端 node:22-alpine → 后端 golang:1.24-alpine → 运行 alpine:3.20,最终体积约 36 MB。
/app/data/initial-credentials.txt(改密成功后自动删除)/app/data 包含 MQTT 账号密码与 JWT 密钥,请限制宿主机目录权限并做好备份7883 到公网Q:登录密码在哪里?
docker exec mgw cat /app/data/initial-credentials.txt
文件不存在说明已经改过密码;忘记密码可停止容器后删除 /app/data/secrets.yaml(会丢失原有账号配置,需重新初始化),或从备份恢复。
Q:容器一直 unhealthy / 打不开页面?
docker logs mgw --tail=100
docker exec mgw wget -qO- http://127.0.0.1/health
常见原因是 26063 端口被占用,或挂载的 config.yaml 路径/权限不对(容器会自动复制并放宽权限,但路径必须存在)。
Q:数据目录权限错误?
容器启动时会自动 chown /app/data 给网关运行用户;使用 bind mount 时请确保宿主机目录可写。
Q:修改了 config.yaml 不生效?
docker restart mgw 重新读取;admin_listen_host/port 改动后 Nginx 反代地址也会失效,不建议修改这两个值。
Q:时间显示是 UTC?
启动时加 -e TZ=Asia/Shanghai(或 compose 里配置 environment.TZ),镜像已包含 tzdata。
Q:能转发 WebSocket / MQTT 5 吗?
目前仅支持 MQTT 3.1.1 的 mqtt:// 与 mqtts://(TLS),不支持 ws/wss 与 MQTT 5。
Q:消息会持久化吗? 连接、分组映射、调试订阅/开关会持久化;转发的消息内容不落盘(仅运行期统计),调试消息日志重启清空。
alpine:3.2080/app/data/app/configs/config.yamlGET /healthlinux/amd64,linux/arm64)请将上述命令中的
sllwakeup/mgw替换为你自己的 Docker Hub 仓库名。
Content type
Image
Digest
sha256:d06e06eac…
Size
9.1 MB
Last updated
3 days ago
docker pull sllwakeup/mgw