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(必须)
|
# 内置路由 nginx(必须)
|
||||||
# 统一处理所有内部路由,直接绑定宿主机 80 端口。
|
# 统一处理所有内部路由,绑定端口由 .env NGINX_BIND 控制:
|
||||||
# 上层 nginx 直接 proxy_pass 到本机 IP:80,宿主机无需额外 nginx 配置。
|
# NGINX_BIND=80 → 直接监听宿主机 80(无宿主机 nginx 场景)
|
||||||
|
# NGINX_BIND=127.0.0.1:11223 → 本地监听(宿主机已有 nginx 场景)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:1.27-alpine
|
image: nginx:1.27-alpine
|
||||||
profiles: ["base"]
|
profiles: ["base"]
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "${NGINX_BIND:-80}:80"
|
||||||
volumes:
|
volumes:
|
||||||
- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
- ./config/nginx/conf.d:/etc/nginx/conf.d: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 配置
|
||||||
|
|
||||||
部署内置了一个 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
|
```nginx
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://192.168.x.x; # 填写部署服务器 IP
|
proxy_pass http://<部署服务器IP>;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection "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 服务名路由到各容器,无需关心具体端口。
|
内置 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,调试用) |
|
| 11224–11231 | 各业务容器(绑定 127.0.0.1,调试用) |
|
||||||
|
|
||||||
各业务容器端口仅用于直接调试,正常流量全部走 80。
|
各业务容器端口仅用于直接调试,正常流量全部走内置 nginx 入口。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -203,6 +203,29 @@ fi
|
|||||||
DEPLOY_HOST="$(printf '%s' "$CONSOLE_BASE" | sed 's|https\?://||')"
|
DEPLOY_HOST="$(printf '%s' "$CONSOLE_BASE" | sed 's|https\?://||')"
|
||||||
ok "外部地址: ${CONSOLE_BASE}"
|
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 — 预检
|
# 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)"
|
fail "磁盘可用空间不足(需 ≥10 GB,当前 ${DISK_FREE_GB:-?} GB)"
|
||||||
ok "磁盘可用: ${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} " || \
|
if ss -tlnp 2>/dev/null | grep -q ":${port} " || \
|
||||||
netstat -tlnp 2>/dev/null | grep -q ":${port} "; then
|
netstat -tlnp 2>/dev/null | grep -q ":${port} "; then
|
||||||
warn "端口 ${port} 已被占用(如已是本脚本的 nginx 容器则无影响,否则会端口冲突)"
|
warn "端口 ${port} 已被占用(如已是本脚本的 nginx 容器则无影响,否则会端口冲突)"
|
||||||
@ -248,9 +272,12 @@ REGISTRY_USER=${REGISTRY_USER}
|
|||||||
REGISTRY_PASSWORD=${REGISTRY_PASSWORD}
|
REGISTRY_PASSWORD=${REGISTRY_PASSWORD}
|
||||||
IMAGE_TAG=${IMAGE_TAG}
|
IMAGE_TAG=${IMAGE_TAG}
|
||||||
|
|
||||||
# 启用全量服务(含内置路由 nginx,宿主机 nginx 只需一条 proxy_pass 到 11223)
|
# 启用全量服务(含内置路由 nginx)
|
||||||
COMPOSE_PROFILES=base,infra-mysql,infra-redis,im,push,update,license
|
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(managed 模式,Docker 容器托管)
|
||||||
MYSQL_MODE=managed
|
MYSQL_MODE=managed
|
||||||
MYSQL_HOST=mysql
|
MYSQL_HOST=mysql
|
||||||
@ -755,13 +782,13 @@ fi
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
step "一键验证所有服务"
|
step "一键验证所有服务"
|
||||||
|
|
||||||
# 验证通过内置 nginx(127.0.0.1:11223)进行,不依赖宿主机或外层 nginx 是否已配置
|
# 验证通过内置 nginx 进行,不依赖宿主机或外层 nginx 是否已配置
|
||||||
# 内置 nginx 已包含全部路由,所有接口均可通过此端口验证
|
_VERIFY_PORT="${NGINX_BIND##*:}"
|
||||||
if BASE_URL="http://127.0.0.1:11223" bash "$ROOT_DIR/scripts/verify.sh"; then
|
if BASE_URL="http://127.0.0.1:${_VERIFY_PORT}" bash "$ROOT_DIR/scripts/verify.sh"; then
|
||||||
ok "全量验证通过"
|
ok "全量验证通过"
|
||||||
else
|
else
|
||||||
printf '\n\033[33m 部分验证项未通过,请查看上方输出。\033[0m\n'
|
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
|
fi
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@ -778,9 +805,26 @@ if [ "$DEPLOY_MODE" = "new" ]; then
|
|||||||
else
|
else
|
||||||
printf ' 密码: 同生产平台密码(原样迁移,未重置)\n'
|
printf ' 密码: 同生产平台密码(原样迁移,未重置)\n'
|
||||||
fi
|
fi
|
||||||
printf '\n \033[1;33m注意(上层 nginx 代理 WebSocket):\033[0m\n'
|
if [ "$_NGINX_MODE" = "proxy" ]; then
|
||||||
printf ' 上层 nginx 指向本机 IP:80 即可,\033[1m无需在宿主机配置 nginx\033[0m。\n'
|
printf '\n \033[1m宿主机 nginx 配置(server 块内加入以下内容):\033[0m\n'
|
||||||
printf ' 但上层每一层 nginx 的 location 块都必须有以下四行透传 WebSocket 升级头:\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'
|
printf '\033[0;37m'
|
||||||
cat <<'WS_NOTE'
|
cat <<'WS_NOTE'
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
@ -789,7 +833,6 @@ cat <<'WS_NOTE'
|
|||||||
proxy_read_timeout 3600s;
|
proxy_read_timeout 3600s;
|
||||||
WS_NOTE
|
WS_NOTE
|
||||||
printf '\033[0m'
|
printf '\033[0m'
|
||||||
printf ' 缺少这四行,IM WebSocket 握手将在任意一层失败。\n'
|
|
||||||
printf '\n \033[1m部署目录:\033[0m %s\n' "$ROOT_DIR"
|
printf '\n \033[1m部署目录:\033[0m %s\n' "$ROOT_DIR"
|
||||||
printf ' \033[1m审计日志:\033[0m %s/logs/audit.log\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}"
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户