尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Nginx反向代理EMQX:HTTPS+MQTT over WSS完整配置

Nginx反向代理EMQX:HTTPS+MQTT over WSS完整配置 Nginx 反向代理 EMQXHTTPS MQTT over WSS 完整配置先说结论Nginx 反向代理 EMQX443 端口同时处理 Web HTTPS 和 MQTT over WSS。设备端用wss://连接Web 端用https://访问。安全、统一、好管理。做物联网平台时设备端通过 MQTT 连接 BrokerWeb 端通过 WebSocket 连接展示实时数据。如果平台部署了 HTTPSMQTT 的明文 1883 端口和 HTTP 的 8083 WebSocket 端口就不能直接暴露。用 Nginx 做反向代理统一走 443 端口 HTTPSMQTT over WSS。一、网络拓扑互联网 │ ├── HTTPS 443 ──→ Nginx ──┬── / → Web前端 (Nginx静态文件) │ ├── /mqtt → EMQX WebSocket (8083) │ └── /api → 后端API (8080) │ └── MQTT 8883 ──→ Nginx ──→ EMQX TLS (8883)二、Nginx 配置完整的 Nginx 配置# /etc/nginx/sites-available/iot-platform # HTTP → HTTPS重定向 server { listen 80; server_name iot.example.com; return 301 https://$server_name$request_uri; } # HTTPS主配置 server { listen 443 ssl; http2 on; server_name iot.example.com; # SSL证书 ssl_certificate /etc/letsencrypt/live/iot.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/iot.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers on; # HSTS add_header Strict-Transport-Security max-age31536000 always; # Web前端静态文件 root /var/www/iot-platform; index index.html; location / { try_files $uri $uri/ /index.html; } # API反向代理 location /api/ { proxy_pass http://127.0.0.1:8080/; 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; } # MQTT over WebSocket location /mqtt { proxy_pass http://127.0.0.1:8083; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 300s; proxy_send_timeout 300s; } } # MQTT TLS 直连代理 stream { server { listen 8883 ssl; ssl_certificate /etc/letsencrypt/live/iot.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/iot.example.com/privkey.pem; proxy_pass 127.0.0.1:1883; } }关键配置解释Upgrade和Connection upgradeWebSocket 升级必需proxy_read_timeout 300sMQTT 长连接默认 60 秒超时会被断开改成 300 秒stream模块处理 TCP 层的 MQTT TLS 直连和 HTTP 的server块分开http2 on启用 HTTP/2提升 Web 性能三、Nginx stream 模块默认 Nginx 不加载 stream 模块。在nginx.conf的最外层加载# /etc/nginx/nginx.conf user www-data; worker_processes auto; events { worker_connections 1024; } http { # ... 其他http配置 include /etc/nginx/sites-enabled/*; } # stream模块必须和http平级 stream { include /etc/nginx/streams-enabled/*; }# 创建stream配置目录sudomkdir/etc/nginx/streams-enabled# 启用stream模块如果用apt安装的nginx默认已编译# 确认模块nginx-V21|grepstream四、EMQX 配置EMQX 端关闭 TLS让 Nginx 处理 TLS 终止# emqx.conflisteners:# MQTT TCPNginx stream代理到这个端口tcp:default:bind:0.0.0.0:1883max_connections:100000# MQTT WebSocketNginx HTTP代理到这个端口ws:default:bind:0.0.0.0:8083max_connections:10000websocket:mqtt_path:/mqtt# 关闭EMQX自带的SSL监听器# ssl:# default:# bind: 0.0.0.0:8883# ssl_options:# keyfile: ...# certfile: ...# 允许WebSocket从Nginx代理连接websocket:origin:https://iot.example.comEMQX 只需要开 1883 和 8083TLS 交给 Nginx 处理。这种方式叫TLS 终止TLS TerminationEMQX 只处理明文数据CPU 开销更低。五、设备端连接设备端用 MQTT over WSS// Web端浏览器constclientnewmqtt.Client(wss://iot.example.com/mqtt,// 走Nginx 443端口client_Math.random().toString(16).substr(2,8));client.onConnect(){console.log(Connected via WSS);client.subscribe(device/001/temperature);};client.connect();# Python设备端设备直连MQTT TLSimportsslimportpaho.mqtt.clientasmqtt clientmqtt.Client()contextssl.create_default_context()context.load_verify_locations(ca.crt)# Lets Encrypt证书链client.tls_set_context(context)client.connect(iot.example.com,8883,60)# 走Nginx stream代理# 或用WebSocketclientmqtt.Client(transportwebsockets)contextssl.create_default_context()context.load_verify_locations(ca.crt)client.tls_set_context(context)client.connect(iot.example.com,443,60)# 走Nginx HTTP代理ESP32 Arduino 端#includeWiFiClientSecure.h#includePubSubClient.hWiFiClientSecure esp_client;PubSubClientmqtt_client(esp_client);voidsetup(){WiFi.begin(SSID,password);// 加载CA证书Lets Encrypt ISRG Root X1constchar*ca_cert\-----BEGIN CERTIFICATE-----\nMIIFazCCB...省略...\n-----END CERTIFICATE-----\n;esp_client.setCACert(ca_cert);// 通过WSS连接443端口mqtt_client.setServer(iot.example.com,443);mqtt_client.setStream(esp_client);// 使用WebSocket路径// PubSubClient不直接支持WSS需要用ESP-MQTT库}ESP-IDF 端用esp-mqtt组件支持 WSS#includemqtt_client.hconstchar*mqtt_uriwss://iot.example.com/mqtt;constchar*cert\-----BEGIN CERTIFICATE-----\n...ISRG Root X1...\n-----END CERTIFICATE-----\n;esp_mqtt_client_config_tmqtt_cfg{.urimqtt_uri,.cert_pemcert,.client_iddevice_001,.lwt_topicdevice/001/status,.lwt_msgoffline,.lwt_qos1,.lwt_retain1,};esp_mqtt_client_handle_tclientesp_mqtt_client_init(mqtt_cfg);esp_mqtt_client_register_event(client,ESP_EVENT_ANY_ID,mqtt_event_handler,NULL);esp_mqtt_client_start(client);六、证书自动续期Let’s Encrypt 证书 90 天过期用 certbot 自动续期# 安装certbotsudoaptinstallcertbot python3-certbot-nginx# 申请证书自动修改Nginx配置sudocertbot--nginx-diot.example.com# 测试续期sudocertbot renew --dry-run# 添加cron定时续期sudocrontab-e# 每月1号凌晨3点检查续期031* * /usr/bin/certbot renew--quiet--post-hooksystemctl reload nginx七、性能调优高并发场景下 Nginx 参数# /etc/nginx/nginx.conf events { worker_connections 10240; # 每个worker最大连接数 use epoll; # Linux高效事件模型 multi_accept on; # 一次accept多个连接 } http { # 连接复用 keepalive_timeout 65; keepalive_requests 1000; # WebSocket特殊处理 map $http_upgrade $connection_upgrade { default upgrade; close; } # Gzip压缩 gzip on; gzip_types text/css application/javascript application/json; # 缓冲区 proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; # 日志格式 log_format mqtt $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent rt$request_time; }系统层面# 文件描述符限制ulimit-n65535# 或永久修改 /etc/security/limits.confnginx soft nofile65535nginx hard nofile65535# 内核参数 /etc/sysctl.confnet.core.somaxconn65535net.ipv4.tcp_max_syn_backlog65535net.ipv4.ip_local_port_range1000065535sudosysctl-p八、实测数据Nginx EMQX 5.02核4GB 服务器指标直连EMQXNginx代理最大WebSocket连接数5000050000消息吞吐100k/s95k/sTLS握手延迟0ms已建连20ms首次连接建立延迟5ms15msCPU占用40%55%内存占用500MB700MB九、踩坑清单WebSocket 路径Nginx 的location /mqtt要和 EMQX 的mqtt_path一致。不一致会 404proxy_read_timeout默认 60 秒。MQTT Keep Alive 通常设 30-120 秒如果 Nginx 超时比 Keep Alive 短连接会被 Nginx 断开HTTP/1.1WebSocket 代理必须设proxy_http_version 1.1默认 1.0 不支持 Upgrade 头stream 模块位置stream 块必须在 nginx.conf 的最外层不能放在 http 块内证书链Let’s Encrypt 的 fullchain.pem 包含中间证书。只发 cert.pem 会导致部分设备验证失败TLS 版本IoT 设备可能不支持 TLSv1.3。ssl_protocols TLSv1.2 TLSv1.3兼容性最好ALPNHTTP/2 需要 ALPN 协商。Nginx 默认支持但如果设备端 mbedTLS 版本低可能协商失败Nginx reload 不中断nginx -s reload不会断开现有连接。但如果 stream 配置改了需要nginx -s reopenX-Forwarded-ForEMQX 拿到的源 IP 是 Nginx 的 127.0.0.1。要在 EMQX 中配置proxy_protocol或从 X-Forwarded-For 头取真实 IP
返回列表