feat(deploy): nginx 绑定模式可选,兼容有/无宿主机 nginx 两种场景
向导新增第 0d 步:询问宿主机 80 端口是否空闲。
- 空闲(多层代理/内网)→ NGINX_BIND=80,容器直接监听宿主机 80
- 已有 nginx(云服务器 HTTPS)→ NGINX_BIND=127.0.0.1:11223,宿主机加一条转发
docker-compose.yml nginx ports 改用 ${NGINX_BIND:-80}:80 变量控制。
端口检查、Step 7 验证地址、部署完成输出均根据模式动态调整。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
8b0c05e0e4
当前提交
0c4802b20a
@ -84,14 +84,15 @@ services:
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 内置路由 nginx(必须)
|
||||
# 统一处理所有内部路由,直接绑定宿主机 80 端口。
|
||||
# 上层 nginx 直接 proxy_pass 到本机 IP:80,宿主机无需额外 nginx 配置。
|
||||
# 统一处理所有内部路由,绑定端口由 .env NGINX_BIND 控制:
|
||||
# NGINX_BIND=80 → 直接监听宿主机 80(无宿主机 nginx 场景)
|
||||
# NGINX_BIND=127.0.0.1:11223 → 本地监听(宿主机已有 nginx 场景)
|
||||
# ---------------------------------------------------------------------------
|
||||
nginx:
|
||||
image: nginx:1.27-alpine
|
||||
profiles: ["base"]
|
||||
ports:
|
||||
- "80:80"
|
||||
- "${NGINX_BIND:-80}:80"
|
||||
volumes:
|
||||
- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./config/nginx/conf.d:/etc/nginx/conf.d:ro
|
||||
|
||||
@ -20,13 +20,15 @@ curl -fsSL https://xuqinmin.com/xuqmGroup/XuqmGroup-PrivateDeploy/raw/branch/mai
|
||||
|
||||
## Nginx 配置
|
||||
|
||||
部署内置了一个 nginx 容器处理所有内部路由,直接绑定宿主机 `0.0.0.0:80`。**宿主机无需任何 nginx 配置。**
|
||||
部署向导会询问宿主机是否已有 nginx,根据答案自动选择绑定模式:
|
||||
|
||||
上层 nginx 直接 `proxy_pass` 指向本机 IP(端口 80)即可,例如:
|
||||
### 场景一:无宿主机 nginx(多层代理 / 内网服务器)
|
||||
|
||||
容器直接绑定宿主机 `0.0.0.0:80`(`NGINX_BIND=80`),上层 nginx 直接指向本机 IP:
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
proxy_pass http://192.168.x.x; # 填写部署服务器 IP
|
||||
proxy_pass http://<部署服务器IP>;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
@ -37,7 +39,24 @@ location / {
|
||||
}
|
||||
```
|
||||
|
||||
> 如果有多层 nginx 代理,**每一层**都必须加上 `proxy_http_version 1.1` 和 `Upgrade`/`Connection` 头,否则 IM WebSocket 握手会在中间某层断开。
|
||||
### 场景二:宿主机已有 nginx(云服务器域名 HTTPS)
|
||||
|
||||
容器绑定 `127.0.0.1:11223`(`NGINX_BIND=127.0.0.1:11223`),宿主机 nginx server 块加一条:
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:11223;
|
||||
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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_read_timeout 3600s;
|
||||
}
|
||||
```
|
||||
|
||||
> **两种场景通用**:每一层 nginx 代理都必须加 `proxy_http_version 1.1` 和 `Upgrade`/`Connection` 头,缺少任意一层 IM WebSocket 就会断开。
|
||||
|
||||
内置 nginx 路由配置在 `config/nginx/conf.d/xuqm.conf`,使用 Docker 服务名路由到各容器,无需关心具体端口。
|
||||
|
||||
@ -47,10 +66,11 @@ location / {
|
||||
|
||||
| 宿主机端口 | 说明 |
|
||||
|-----------|------|
|
||||
| **80** | 内置 nginx 入口(上层 nginx 直接指向此端口) |
|
||||
| **80** | 内置 nginx 入口(无宿主机 nginx 场景,`NGINX_BIND=80`) |
|
||||
| **11223** | 内置 nginx 入口(有宿主机 nginx 场景,`NGINX_BIND=127.0.0.1:11223`) |
|
||||
| 11224–11231 | 各业务容器(绑定 127.0.0.1,调试用) |
|
||||
|
||||
各业务容器端口仅用于直接调试,正常流量全部走 80。
|
||||
各业务容器端口仅用于直接调试,正常流量全部走内置 nginx 入口。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -203,6 +203,29 @@ fi
|
||||
DEPLOY_HOST="$(printf '%s' "$CONSOLE_BASE" | sed 's|https\?://||')"
|
||||
ok "外部地址: ${CONSOLE_BASE}"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 0d. 宿主机 nginx 模式
|
||||
# ---------------------------------------------------------------------------
|
||||
printf '\n\033[1;33m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n'
|
||||
printf '\033[1;33m 宿主机 nginx 模式\033[0m\n'
|
||||
printf '\033[1;33m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n'
|
||||
printf ' 1) 宿主机 80 端口空闲 — 容器直接监听 80,上层代理无需宿主机 nginx\n'
|
||||
printf ' (适合:多层 nginx 代理、无宿主机 nginx 的内网服务器)\n'
|
||||
printf ' 2) 宿主机已有 nginx — 容器监听本地 127.0.0.1:11223,宿主机 nginx 加一条转发\n'
|
||||
printf ' (适合:云服务器域名 HTTPS 场景,宿主机 nginx 处理证书)\n\n'
|
||||
|
||||
_NGINX_MODE=""
|
||||
NGINX_BIND="80"
|
||||
while [ -z "$_NGINX_MODE" ]; do
|
||||
read -rp " 请选择 [1/2]: " _choice
|
||||
case "$_choice" in
|
||||
1) _NGINX_MODE="direct"; NGINX_BIND="80" ;;
|
||||
2) _NGINX_MODE="proxy"; NGINX_BIND="127.0.0.1:11223" ;;
|
||||
*) printf ' 请输入 1 或 2\n' ;;
|
||||
esac
|
||||
done
|
||||
ok "nginx 入口: ${NGINX_BIND}:80"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Step 1 — 预检
|
||||
# ---------------------------------------------------------------------------
|
||||
@ -220,7 +243,8 @@ DISK_FREE_GB="$(df -BG "$ROOT_DIR" | awk 'NR==2{gsub(/G/,"",$4); print $4}')"
|
||||
fail "磁盘可用空间不足(需 ≥10 GB,当前 ${DISK_FREE_GB:-?} GB)"
|
||||
ok "磁盘可用: ${DISK_FREE_GB} GB"
|
||||
|
||||
for port in 80; do
|
||||
_NGINX_PORT="${NGINX_BIND##*:}" # 从 "80" 或 "127.0.0.1:11223" 提取端口号
|
||||
for port in "$_NGINX_PORT"; do
|
||||
if ss -tlnp 2>/dev/null | grep -q ":${port} " || \
|
||||
netstat -tlnp 2>/dev/null | grep -q ":${port} "; then
|
||||
warn "端口 ${port} 已被占用(如已是本脚本的 nginx 容器则无影响,否则会端口冲突)"
|
||||
@ -248,9 +272,12 @@ REGISTRY_USER=${REGISTRY_USER}
|
||||
REGISTRY_PASSWORD=${REGISTRY_PASSWORD}
|
||||
IMAGE_TAG=${IMAGE_TAG}
|
||||
|
||||
# 启用全量服务(含内置路由 nginx,宿主机 nginx 只需一条 proxy_pass 到 11223)
|
||||
# 启用全量服务(含内置路由 nginx)
|
||||
COMPOSE_PROFILES=base,infra-mysql,infra-redis,im,push,update,license
|
||||
|
||||
# nginx 入口绑定(80=直接监听宿主机80;127.0.0.1:11223=本地监听需宿主机nginx转发)
|
||||
NGINX_BIND=${NGINX_BIND}
|
||||
|
||||
# MySQL(managed 模式,Docker 容器托管)
|
||||
MYSQL_MODE=managed
|
||||
MYSQL_HOST=mysql
|
||||
@ -755,13 +782,13 @@ fi
|
||||
# ---------------------------------------------------------------------------
|
||||
step "一键验证所有服务"
|
||||
|
||||
# 验证通过内置 nginx(127.0.0.1:11223)进行,不依赖宿主机或外层 nginx 是否已配置
|
||||
# 内置 nginx 已包含全部路由,所有接口均可通过此端口验证
|
||||
if BASE_URL="http://127.0.0.1:11223" bash "$ROOT_DIR/scripts/verify.sh"; then
|
||||
# 验证通过内置 nginx 进行,不依赖宿主机或外层 nginx 是否已配置
|
||||
_VERIFY_PORT="${NGINX_BIND##*:}"
|
||||
if BASE_URL="http://127.0.0.1:${_VERIFY_PORT}" bash "$ROOT_DIR/scripts/verify.sh"; then
|
||||
ok "全量验证通过"
|
||||
else
|
||||
printf '\n\033[33m 部分验证项未通过,请查看上方输出。\033[0m\n'
|
||||
printf ' 可重新运行:BASE_URL=http://127.0.0.1:11223 bash %s/scripts/verify.sh\n' "$ROOT_DIR"
|
||||
printf ' 可重新运行:BASE_URL=http://127.0.0.1:%s bash %s/scripts/verify.sh\n' "$_VERIFY_PORT" "$ROOT_DIR"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@ -778,9 +805,26 @@ if [ "$DEPLOY_MODE" = "new" ]; then
|
||||
else
|
||||
printf ' 密码: 同生产平台密码(原样迁移,未重置)\n'
|
||||
fi
|
||||
printf '\n \033[1;33m注意(上层 nginx 代理 WebSocket):\033[0m\n'
|
||||
printf ' 上层 nginx 指向本机 IP:80 即可,\033[1m无需在宿主机配置 nginx\033[0m。\n'
|
||||
printf ' 但上层每一层 nginx 的 location 块都必须有以下四行透传 WebSocket 升级头:\n'
|
||||
if [ "$_NGINX_MODE" = "proxy" ]; then
|
||||
printf '\n \033[1m宿主机 nginx 配置(server 块内加入以下内容):\033[0m\n'
|
||||
printf '\033[0;37m'
|
||||
cat <<'NGINX_REF'
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:11223;
|
||||
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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_read_timeout 3600s;
|
||||
}
|
||||
NGINX_REF
|
||||
printf '\033[0m'
|
||||
else
|
||||
printf '\n 宿主机无需 nginx 配置,上层 proxy_pass 直接指向本机 IP:80 即可。\n'
|
||||
fi
|
||||
printf '\n \033[1;33m注意:\033[0m每一层 nginx 代理都必须透传以下 WebSocket 升级头,否则 IM 连接失败:\n'
|
||||
printf '\033[0;37m'
|
||||
cat <<'WS_NOTE'
|
||||
proxy_http_version 1.1;
|
||||
@ -789,7 +833,6 @@ cat <<'WS_NOTE'
|
||||
proxy_read_timeout 3600s;
|
||||
WS_NOTE
|
||||
printf '\033[0m'
|
||||
printf ' 缺少这四行,IM WebSocket 握手将在任意一层失败。\n'
|
||||
printf '\n \033[1m部署目录:\033[0m %s\n' "$ROOT_DIR"
|
||||
printf ' \033[1m审计日志:\033[0m %s/logs/audit.log\n' "$ROOT_DIR"
|
||||
printf '\n\033[1;32m 部署成功!上层 nginx proxy_pass 指向本机 IP:80 后即可访问:%s\033[0m\n\n' "${CONSOLE_BASE}"
|
||||
printf '\n\033[1;32m 部署成功!可访问:%s\033[0m\n\n' "${CONSOLE_BASE}"
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户