Nginx 通过 stream 模块可实现 MQTT 四层代理,支持负载均衡、TLS 终止与访问控制,但不解析 MQTT 协议,仅透传 TCP 流;需启用 --with-stream,配置在 http 块外,支持 1883/8883 端口及 IP 白名单等基础策略。

Nginx 本身不原生支持 MQTT 协议解析,但自 1.9.0 版本起引入了 stream 模块,可用于四层(TCP/UDP)代理。借助该模块,Nginx 可作为轻量、高并发的 MQTT 网关,实现连接负载均衡、TLS 终止、访问控制和后端服务路由等能力——关键在于它不解析 MQTT 报文,而是透传 TCP 流,因此对 MQTT 协议版本(3.1.1 / 5.0)、客户端行为完全透明。
启用 stream 模块并配置基础 TCP 代理
确认 Nginx 编译时已启用 --with-stream(主流发行版包通常默认开启)。在主配置文件(如 /etc/nginx/nginx.conf)顶部添加:
stream {
upstream mqtt_backend {
server 192.168.1.10:1883; # 实际 MQTT Broker 地址
server 192.168.1.11:1883;
# 可配 weight、max_fails、fail_timeout 等负载策略
}
<pre class="brush:php;toolbar:false;">server {
listen 1883;
proxy_pass mqtt_backend;
proxy_timeout 1h;
proxy_responses 1; # MQTT 连接长期存活,禁用响应计数限制
}
}
注意:stream 块必须位于 http 块之外,且 reload 配置需用 nginx -s reload(非 restart)。
为 MQTT 添加 TLS 加密(端口 8883)
MQTT over TLS(即 mqtts)要求 Nginx 终止 TLS 并将明文 TCP 流转发至后端。配置示例如下:
server {
listen 8883 ssl;
ssl_certificate /etc/nginx/ssl/mqtt.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/mqtt.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
<pre class="brush:php;toolbar:false;">proxy_pass mqtt_backend;
proxy_timeout 1h;
}
⚠️ 注意事项:
- MQTT 客户端需信任该证书(或使用私有 CA),否则连接会因证书校验失败中断
- 若后端 Broker 也启用 TLS,Nginx 仅作 TLS 终止,后端通信走明文(推荐内网环境);如需端到端加密,应由 Broker 自行处理,Nginx 不参与
- 避免在 stream 层做 SNI 路由(MQTT 客户端通常不发送 SNI),故单域名证书即可
结合 realip 和日志实现简单访问控制与审计
stream 模块支持 set_real_ip_from 和 real_ip_header(需搭配前置 L4 负载设备),也可通过 log_format 记录连接元数据:
log_format mqtt_log '$remote_addr:$remote_port - [$time_local] '
'$session_time "$upstream_addr" $upstream_bytes_sent';
<p>access_log /var/log/nginx/mqtt_access.log mqtt_log;</p>进一步可利用 map 指令 + deny/allow 实现 IP 白名单:
stream {
map $remote_addr $allowed {
default 0;
192.168.1.0/24 1;
2001:db8::/32 1;
}
<pre class="brush:php;toolbar:false;">server {
listen 1883;
if ($allowed = 0) { return 403; } # 注意:stream 中 if 仅支持简单比较
proxy_pass mqtt_backend;
}
}
更精细控制(如基于 clientID 或 username)需依赖后端 Broker 的认证机制,Nginx 无法解析 MQTT CONNECT 包字段。
常见问题与调优提示
-
连接超时断连:确保
proxy_timeout大于客户端 keepalive 值(如设为 1.5 倍 keepalive),避免 Nginx 主动断链 -
大量 TIME_WAIT:在系统层面调优
net.ipv4.tcp_tw_reuse=1,Nginx 无需特殊配置 -
无法代理 WebSocket MQTT(ws/wss):WebSocket 是 HTTP 升级协议,必须用
http块中的location配置,不可放在 stream 中 -
健康检查缺失:stream 模块原生不支持 TCP 健康检查;可用
health_check(商业版)或配合外部脚本 +upstream_conf模块动态管理











