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

如何通过NGINX实现Docker动态端口下NodeJS+Socket.io应用的域名访问

动态Docker容器+Socket.IO的Nginx反向代理配置方案

嘿,这个需求我之前帮朋友落地过,核心难点就是动态端口的映射匹配和Socket.IO的WebSocket兼容配置,我给你整理了两种靠谱的方案,按需选就行:

核心思路先理清楚

你的Web应用会动态创建Docker容器并分配随机/动态端口,Nginx没法提前写死配置,所以核心是要让Nginx能实时获取「自定义域名 ↔ 容器端口/地址」的映射关系,再配合Socket.IO专属的反向代理配置,就能实现域名直接访问了。


方案一:用OpenResty(带Lua的Nginx)实时查询映射

这个方案最灵活,实时性拉满,不用频繁重启Nginx。

步骤1:准备OpenResty

直接装OpenResty就行,它自带Lua模块,省得自己编译Nginx加Lua:

# Ubuntu/Debian示例
apt update && apt install openresty

步骤2:存储「域名-端口/容器地址」映射

你的Web应用在创建Docker容器时,得把自定义域名和访问地址(宿主机端口或者Docker容器名+内部端口)存到一个快速查询的地方,比如Redis:

  • 创建容器时执行:redis-cli SET myapp.yourdomain.com 30001(假设映射到宿主机30001端口)
  • 如果用Docker网络,就存容器名:redis-cli SET myapp.yourdomain.com myapp-123:3000
  • 删除容器时执行:redis-cli DEL myapp.yourdomain.com

步骤3:配置OpenResty

把下面的配置放到/usr/local/openresty/nginx/conf/nginx.conf(或你的Nginx配置目录):

http {
    # 开辟共享内存存临时缓存,减少Redis查询次数
    lua_shared_dict addr_cache 10m;

    server {
        listen 80;
        server_name _; # 匹配所有域名,也可以写你的域名前缀比如 *.yourdomain.com

        location / {
            content_by_lua_block {
                -- 获取当前请求的域名
                local domain = ngx.var.host
                -- 先查缓存,没有再查Redis
                local cache = ngx.shared.addr_cache
                local target_addr = cache:get(domain)

                if not target_addr then
                    -- 连接Redis查询
                    local redis = require "resty.redis"
                    local red = redis:new()
                    red:set_timeout(1000)
                    local ok, err = red:connect("127.0.0.1", 6379)
                    if not ok then
                        ngx.log(ngx.ERR, "Redis连接失败: ", err)
                        ngx.exit(500)
                    end
                    target_addr, err = red:get(domain)
                    if not target_addr or target_addr == ngx.null then
                        ngx.exit(404)
                    end
                    -- 缓存10分钟,避免频繁查Redis
                    cache:set(domain, target_addr, 600)
                end

                -- 把目标地址传给反向代理变量
                ngx.var.proxy_target = "http://" .. target_addr
            }

            -- 实际反向代理配置
            proxy_pass $proxy_target;

            # 敲黑板!Socket.IO必须的配置,少一个都可能连不上
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

步骤4:重启OpenResty

openresty -s reload

方案二:用Consul+Consul-Template自动生成Nginx配置

如果你的架构已经用了服务注册中心,这个方案更规整,不用写Lua脚本。

步骤1:部署Consul和Consul-Template

Consul用来注册服务(域名+访问地址),Consul-Template监听Consul的变化,自动生成Nginx配置并reload。

步骤2:注册服务到Consul

你的Web应用创建容器时,向Consul注册服务:

# 示例:注册myapp.yourdomain.com,端口30001,标签标记是socketio服务
curl -X PUT http://localhost:8500/v1/agent/service/register -d '{
  "Name": "myapp.yourdomain.com",
  "Port": 30001,
  "Tags": ["socketio"]
}'

删除容器时注销服务:

curl -X PUT http://localhost:8500/v1/agent/service/deregister/myapp.yourdomain.com

步骤3:写Consul-Template模板

创建nginx.ctmpl文件:

http {
    server {
        listen 80;
        charset utf-8;

        {{ range services }}
            {{ if .Tags | contains "socketio" }}
                server_name {{ .Name }};
                location / {
                    proxy_pass http://127.0.0.1:{{ .Port }};

                    # Socket.IO必备配置
                    proxy_http_version 1.1;
                    proxy_set_header Upgrade $http_upgrade;
                    proxy_set_header Connection "upgrade";
                    proxy_set_header Host $host;
                    proxy_cache_bypass $http_upgrade;
                }
            {{ end }}
        {{ end }}
    }
}

步骤4:启动Consul-Template

让它自动生成配置并reload Nginx:

consul-template -consul-addr=localhost:8500 -template="nginx.ctmpl:/etc/nginx/conf.d/socketio.conf:nginx -s reload"

额外优化建议:用Docker网络代替宿主机端口映射

如果你的Nginx也是跑在Docker容器里,强烈建议把Nginx和应用容器放到同一个Docker网络里:

  • 创建Docker网络:docker network create app-network
  • 启动Nginx容器时加入这个网络:docker run -d --network app-network ... nginx
  • 应用容器启动时也加入这个网络:docker run -d --network app-network --name myapp-123 ... your-node-app
  • 这时候反向代理的目标就变成http://myapp-123:3000(假设应用内部端口是3000),不用再暴露端口到宿主机,更安全也更省心。

内容的提问来源于stack exchange,提问作者Sajjad Ahmed Shaaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 18:18:11