一台服务器部署多个服务:Dockge + Nginx Proxy Manager + 3X-UI 端口复用与 HTTPS 教程
最终效果:一台 VPS 上同时运行多个 Web 服务,只有 Nginx Proxy Manager 占用公网 80/443;其他服务使用独立内部端口,再通过不同子域名访问。本文从零开始,部署完成后逐项验证 HTTPS、反向代理、容器状态和管理面板。
先确定最终架构,不要边装边改端口
| 子域名示例 | 服务 | 后端端口 | 是否直接公网开放 |
|---|---|---|---|
dockge.example.com | Dockge | 5001 | 不建议 |
npm.example.com | NPM Admin | 81 | 限制来源 |
ip.example.com | MyIP | 18966 | 否 |
tools.example.com | IT-Tools | 8088 | 否 |
panel.example.com | 3X-UI | 2053 示例 | 否 |
检查服务器、Docker 与端口占用
建议使用 Ubuntu 22.04/24.04 或 Debian 11/12。Docker 和 Compose V2 应已经安装。
docker --version
docker compose version
sudo ss -lntp | grep -E ':(80|81|443|5001|18966|8088|2053)\b' || true为每个服务准备 DNS 记录
| 类型 | 名称 | 目标 |
|---|---|---|
| A | dockge | 你的 VPS IPv4 |
| A | ip | 你的 VPS IPv4 |
| A | tools | 你的 VPS IPv4 |
| A | panel | 你的 VPS IPv4 |
dig +short dockge.example.com
dig +short ip.example.com
dig +short tools.example.com
dig +short panel.example.com部署 Dockge:以后用它管理 Compose 栈
/opt/stacks。Dockge 官方 Compose 当前使用 louislam/dockge:1,默认 Web 端口 5001,并要求 stacks 目录左右挂载路径保持完全一致。
sudo mkdir -p /opt/stacks /opt/dockge
cd /opt/dockge
sudo curl -L \
https://raw.githubusercontent.com/louislam/dockge/master/compose.yaml \
-o compose.yaml
sudo docker compose up -d
sudo docker compose ps
curl -I http://127.0.0.1:5001
docker ps --filter name=dockgehttp://服务器IP:5001 可以进入 Dockge 初始化页面;容器状态为 Up。在 Dockge 创建 Nginx Proxy Manager 栈
在 Dockge 点击 Compose → New Stack,名称建议填写 npm,然后写入:
services:
app:
image: jc21/nginx-proxy-manager:2.15.1
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- "80:80"
- "81:81"
- "443:443"
environment:
TZ: "Asia/Shanghai"
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt点击 Deploy。NPM 官方当前 Quick Setup 仍使用 80、81、443,其中 81 是管理 UI。

sudo ss -lntp | grep -E ':(80|81|443)\b'
curl -I http://127.0.0.1:81http://服务器IP:81 能打开管理界面。部署 MyIP,并把真实域名加入允许列表
MyIP 当前官方文档明确要求真实域名场景配置 ALLOWED_DOMAINS;完整地理位置和 ASN 查询还需要免费的 MaxMind GeoLite2 凭据。
services:
myip:
image: jason5ng32/myip:latest
container_name: myip
restart: always
ports:
- "18966:18966"
environment:
ALLOWED_DOMAINS: "ip.example.com"
MAXMIND_ACCOUNT_ID: "YOUR_ACCOUNT_ID"
MAXMIND_LICENSE_KEY: "YOUR_LICENSE_KEY"
MAXMIND_AUTO_UPDATE: "true"
curl -I http://127.0.0.1:18966
docker logs --tail=50 myipALLOWED_DOMAINS 是否和实际访问域名完全一致。部署 IT-Tools 工具箱
services:
it-tools:
image: corentinth/it-tools:latest
container_name: it-tools
restart: unless-stopped
ports:
- "8088:80"
curl -I http://127.0.0.1:8088
docker ps --filter name=it-tools在 NPM 创建 Proxy Host,并申请 HTTPS
进入 NPM:Hosts → Proxy Hosts → Add Proxy Host。

| 域名 | Scheme | Forward Host | Port |
|---|---|---|---|
ip.example.com | http | 宿主机可达地址 | 18966 |
tools.example.com | http | 宿主机可达地址 | 8088 |
dockge.example.com | http | 宿主机可达地址 | 5001 |
然后切到 SSL 标签:
- Request a new SSL Certificate
- Force SSL
- HTTP/2 Support
- 同意 Let's Encrypt 条款
curl -I https://ip.example.com
curl -I https://tools.example.com
curl -I https://dockge.example.com127.0.0.1 指向 NPM 容器自己。可通过共享 Docker network,或配置 host.docker.internal:host-gateway 访问宿主机服务。安装 3X-UI,并先只验证面板本身
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/master/install.sh)
x-ui安装后通过菜单确认:
| 配置 | 说明 |
|---|---|
webPort | 当前官方默认值为 2053,实际以你的配置为准 |
webBasePath | 建议使用随机、非默认路径 |
webCertFile / webKeyFile | 如果 TLS 交给 NPM,这里可以不配置 |

sudo ss -lntp | grep ':2053' || true
curl -I http://127.0.0.1:2053用 NPM 反向代理 3X-UI,并开启 WebSocket
https://panel.example.com 访问面板,隐藏真实管理端口。3X-UI 当前官方文档明确说明:面板实时更新依赖 WebSocket,因此反向代理必须正确处理 Upgrade/Connection。
| NPM 字段 | 填写值 |
|---|---|
| Domain Names | panel.example.com |
| Scheme | http |
| Forward Hostname / IP | NPM 能访问宿主机的地址 |
| Forward Port | 2053 示例 |
| Websockets Support | 开启 |
SSL 标签继续申请 Let's Encrypt 并开启 Force SSL。
curl -I https://panel.example.com
curl -I https://panel.example.com/你的WebBasePath/:2053。收口公网端口:只留下真正需要的入口
| 端口 | 最终建议 |
|---|---|
| 80 / 443 | 公网开放,交给 NPM |
| 81 | 仅可信 IP / VPN / 内网访问 |
| 5001 | 仅 NPM 或可信网络访问 |
| 18966 | 不作为公网入口 |
| 8088 | 不作为公网入口 |
| 2053 | 不作为公网入口 |
sudo ss -lntp | grep -E ':(80|81|443|5001|18966|8088|2053)\b'
docker ps --format 'table {{.Names}}\t{{.Ports}}\t{{.Status}}'127.0.0.1:端口:容器端口,或者全部加入 NPM 的共享 Docker network,减少宿主机公开监听。最终验收:不要只看“页面能打开”
docker compose ps/ Dockge 中所有 Stack 状态正常。- 每个子域名 HTTPS 返回正常,不出现证书警告。
- NPM Proxy Hosts 状态 Online。
- MyIP 不出现 403,MaxMind 功能可用。
- IT-Tools 能实际打开一个工具并正常操作。
- 3X-UI 登录和实时状态正常,WebSocket 没有断开。
- 重启服务器或容器后,所有服务能自动恢复。
/opt/stacks、NPM data/letsencrypt 等持久化目录已备份。
for url in \
https://dockge.example.com \
https://ip.example.com \
https://tools.example.com \
https://panel.example.com; do
echo "== $url =="
curl -sS -o /dev/null -w '%{http_code} %{ssl_verify_result}\n' "$url"
done故障排查:按现象定位,不要反复重装
| 现象 | 常见原因 | 检查 / 修复 |
|---|---|---|
| NPM 启动失败 | 80/81/443 被占用 | ss -lntp 找到占用进程;只能保留一个公网反代入口 |
| NPM 502 Bad Gateway | Forward Host / Port 不可达 | 从 NPM 容器内测试后端地址;不要误用容器内 127.0.0.1 |
| MyIP 403 | ALLOWED_DOMAINS 未配置 | 加入实际访问域名并重启 MyIP |
| MyIP 地理数据 503 | 缺 MaxMind 凭据 | 配置 GeoLite2 Account ID / License Key |
| 3X-UI 页面能开但状态不刷新 | WebSocket 未代理 | NPM 开启 Websockets Support,确认代理链路支持 Upgrade |
| HTTPS 申请失败 | DNS 未生效或 80 被其它服务截获 | dig 检查 IP;确认 NPM 能收到 ACME HTTP Challenge |
| 重启后数据消失 | Compose 没有正确持久化 | 检查 volume 路径并备份 /opt/stacks 与应用 data 目录 |
部署完成后的结构
80/443 → Nginx Proxy Manager → Dockge / MyIP / IT-Tools / 3X-UI
Dockge 官方 Compose:louislam/dockge · NPM:nginxproxymanager.com · MyIP:jason5ng32/MyIP · IT-Tools:CorentinTh/it-tools · 3X-UI:MHSanaei/3x-ui
