You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nginx反向代理Mosquitto配置问题求助

问题排查:Nginx代理MQTT集群订阅仅收半数消息

我参考了Stack Overflow上的MQTT反向代理配置帖子,在虚拟机中用Nginx监听1885端口,希望实现消息在多个Mosquitto容器间分发,构建MQTT集群。


初始配置及问题

docker-compose.yml

version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - "1885:1885"
      - "443:443"
    volumes:
      - ./nginx.conf:/var/lib/docker/volumes/nginx-conf/_data/nginx.conf
    networks:
      - backend

  mosquitto1:
    image: eclipse-mosquitto
    ports:
      - "1886:1886"
    environment:
      - listener=1886:1886
      - allow_anonymous=true
    networks:
      - backend
    volumes:
      - ./mosquitto.conf:/etc/mosquitto/mosquitto.conf

networks:
  backend:
    driver: bridge

nginx.conf

events {
}

http {
    upstream mosquitto_backend {
        
    zone tcp_mem 64k;
    proxy_protocol on;
    }

    server {
        listen 1885;
        server_name localhost;
    log_format mqtt '$remote_addr [$time_local] $protocol $status $bytes_sent $bytes_received $session_time "$request" "$http_referer" "$http_user_agent" "$upstream_addr"';
    access_log /var/log/nginx/mqtt_access.log mqtt;
    error_log  /var/log/nginx/mqtt_error.log; # Health check notifications
        location / {
            proxy_pass http://mosquitto_backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

初始问题

  • 能订阅1885端口,但无法从其他终端发布消息,也无法用MQTT Explorer连接
  • 启动docker-compose时,Mosquitto容器提示1883端口地址不可用,但宿主机通过lsof/netstat检查该端口未被占用

更新后配置及当前问题

docker-compose.yml

version: '3'
services:
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "1885:1885"
      - "443:443"
    volumes:
      - /var/lib/docker/volumes/nginx-conf/_data:/etc/nginx
    depends_on:
      - mosquitto1
      - mosquitto2
    networks:
      - backend

  mosquitto1:
    image: eclipse-mosquitto
    container_name: mosquitto1
    ports:
      - "1886:1883"
    networks:
      - backend
    volumes:
      - /var/lib/docker/volumes/docker-compose-conf/_data/mosquitto/config:/mosquitto/config    
  mosquitto2:
    image: eclipse-mosquitto
    container_name: mosquitto2
    ports:
      - "1887:1883"
    networks:
      - backend
    volumes:
      - /var/lib/docker/volumes/docker-compose-conf/_data/mosquitto/config:/mosquitto/config

networks:
  backend:
    driver: bridge

nginx.conf

events {
  worker_connections  4096;  ## Default: 1024
}


stream {

        log_format mqtt '$remote_addr [$time_local] $protocol $status $bytes_received ' 
                '$bytes_sent $upstream_addr';
    
    upstream mqtt_cluster {
        server 192.168.210.36:1886; #mosquitto1 | 192.168.210.35
        server 192.168.210.36:1887; #mosquitto2 | 192.168.210.39
    }


    server {
        listen 1885;
        proxy_pass mqtt_cluster;
       

        access_log /var/log/nginx/mqtt_access.log mqtt;
        
    }
}   

mosquitto.conf

# =================================================================
# Default listener
# =================================================================

# Port to use for the default listener.
listener 1883
allow_anonymous true
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log

当前问题

所有容器正常启动,Nginx负载均衡能将消息分发到1886和1887端口的容器,但订阅1885端口的客户端只能收到半数消息——仅保留单个Mosquitto容器时,所有消息能正常接收,怀疑是配置导致两个容器存在覆盖冲突。


核心问题排查与修复

1. docker-compose.yml的共享卷冲突(直接导致消息丢失)

两个Mosquitto容器挂载了同一宿主机目录到容器内的/mosquitto/config,同时默认的/mosquitto/data和/mosquitto/log也会因为基础镜像的配置,最终共享宿主机的同一目录:

  • 当两个容器同时运行时,它们的配置文件、持久化数据、日志会互相覆盖,导致只有一个容器能正常处理消息,客户端自然只能收到半数消息。

修复方案:为每个Mosquitto容器分配独立的挂载目录:

mosquitto1:
  image: eclipse-mosquitto
  container_name: mosquitto1
  ports:
    - "1886:1883"
  networks:
    - backend
  volumes:
    - /var/lib/docker/volumes/docker-compose-conf/_data/mosquitto/config1:/mosquitto/config
    - /var/lib/docker/volumes/docker-compose-conf/_data/mosquitto/data1:/mosquitto/data
    - /var/lib/docker/volumes/docker-compose-conf/_data/mosquitto/log1:/mosquitto/log    
mosquitto2:
  image: eclipse-mosquitto
  container_name: mosquitto2
  ports:
    - "1887:1883"
  networks:
    - backend
  volumes:
    - /var/lib/docker/volumes/docker-compose-conf/_data/mosquitto/config2:/mosquitto/config
    - /var/lib/docker/volumes/docker-compose-conf/_data/mosquitto/data2:/mosquitto/data
    - /var/lib/docker/volumes/docker-compose-conf/_data/mosquitto/log2:/mosquitto/log

确保每个configX目录下都有独立的mosquitto.conf(内容可一致,但路径必须分开)。

2. Nginx负载均衡策略优化

当前Nginx使用宿主机IP+端口的方式连接Mosquitto容器,存在两个问题:

  • 依赖宿主机端口映射,增加网络转发损耗
  • 默认轮询策略会导致同一客户端的订阅、发布请求被分到不同节点,而独立Mosquitto节点间没有消息同步,客户端收不到跨节点的消息

修复方案:

  • 使用Docker服务名直接通信(桥接网络内可直接通过服务名访问)
  • 添加ip_hash策略,保证同一客户端始终连接到同一节点:
upstream mqtt_cluster {
    server mosquitto1:1883;
    server mosquitto2:1883;
    ip_hash;
}

3. 补充Mosquitto节点消息同步(集群核心)

仅靠Nginx负载均衡只是实现了流量分发,两个Mosquitto节点仍是独立个体,跨节点的消息无法互通。需要添加桥接配置实现消息同步:

在mosquitto1的mosquitto.conf中添加:

connection mosquitto2
address mosquitto2:1883
topic # both 0

在mosquitto2的mosquitto.conf中添加:

connection mosquitto1
address mosquitto1:1883
topic # both 0

该配置会让两个节点同步所有主题的消息,确保客户端无论连接到哪个节点,都能收到所有发布的消息。


内容的提问来源于stack exchange,提问作者adrian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 13:45:17