From 38c4c465c5af7c387b91a8f7ce76580a284ad156 Mon Sep 17 00:00:00 2001 From: whm <973418690@qq.com> Date: Fri, 27 Mar 2026 11:15:00 +0800 Subject: [PATCH] =?UTF-8?q?feat(deploy):=20=E5=AE=BF=E4=B8=BB=E6=9C=BA?= =?UTF-8?q?=E5=8D=95=20Nginx=20=E6=96=B9=E6=A1=88=E3=80=81compose=20?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E4=B8=8E=E5=90=AF=E5=8A=A8=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- docker-compose.host-nginx.yml | 20 ++++++ nginx/README.md | 32 ++++++++++ nginx/yuheng.host.conf | 105 +++++++++++++++++++++++++++++++ scripts/start-with-host-nginx.sh | 52 +++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 docker-compose.host-nginx.yml create mode 100644 nginx/yuheng.host.conf create mode 100644 scripts/start-with-host-nginx.sh diff --git a/docker-compose.host-nginx.yml b/docker-compose.host-nginx.yml new file mode 100644 index 0000000..1a3804d --- /dev/null +++ b/docker-compose.host-nginx.yml @@ -0,0 +1,20 @@ +# 与 docker-compose.yml 合并使用:宿主机 Nginx 独占 443 时,不要启动容器 yh_nginx。 +# 并为 api / web / admin 绑定本机回环端口,供宿主机 Nginx 反代(见 nginx/yuheng.host.conf)。 +# +# docker compose -f docker-compose.yml -f docker-compose.host-nginx.yml up -d +# +# 容器内 Nginx(旧方案)需显式启用 profile: +# docker compose --profile compose-internal-nginx up -d +services: + api: + ports: + - "127.0.0.1:8088:8088" + web: + ports: + - "127.0.0.1:9080:80" + admin: + ports: + - "127.0.0.1:9081:80" + nginx: + profiles: + - compose-internal-nginx diff --git a/nginx/README.md b/nginx/README.md index c939939..4fb8c2a 100644 --- a/nginx/README.md +++ b/nginx/README.md @@ -80,3 +80,35 @@ sudo systemctl start nginx - **要求**:托管 **web 前台** 的站点必须使用 **`try_files $uri $uri/ /index.html;`**(见仓库 `nginx/web.conf` 与 `web/Dockerfile` 内嵌配置)。若你自建 Nginx,请对照修改后再 `nginx -t` 并重载。 - **应用内 404**:在 SPA 已正确回退的前提下,未在后台发布的路径会由前端路由进入 **「页面不存在」** 页(`NotFound.vue`),与上述 nginx 404 不同。 - **Compose 部署**:`web` 容器实际加载的是 **`deploy/web/default.conf`**(见 `docker-compose.yml` 挂载)。若线上仍对 `/test` 等返回 **nginx 404**,请把仓库里最新的 `deploy/web/default.conf` 同步到服务器对应路径后,执行 `docker compose restart web`(或重建 `yh_web` 容器)。 + +## 6. 单实例:仅宿主机 Nginx(推荐一台机一个 443 入口) + +不再使用容器 **`yh_nginx`**,由**宿主机 Nginx** 监听 **443**,把流量转到本机回环上的 **`web` / `admin` / `api` 容器**。 + +1. **证书**:同上,放在 `/etc/ssl/yh_web/yuheng.yuxindazhineng.com/`。 +2. **合并 Compose**(为容器绑定回环端口,并禁用 compose 内 Nginx): + +```bash +docker compose -f docker-compose.yml -f docker-compose.host-nginx.yml up -d mongo api web admin +``` + +3. **一键脚本**(启动容器 + 写入宿主机站点配置并重载 Nginx): + +```bash +chmod +x scripts/start-with-host-nginx.sh +./scripts/start-with-host-nginx.sh +``` + +脚本会把 `nginx/yuheng.host.conf` 中的 `__VERIFY_ROOT__` 替换为项目下 `verify-root` 绝对路径,并写入 `/etc/nginx/conf.d/yuheng.yuxindazhineng.com.conf`(需 **sudo**)。若不想自动改 Nginx,可 `INSTALL_NGINX_CONF=0 ./scripts/start-with-host-nginx.sh`。 + +4. **回环端口约定**(与 `nginx/yuheng.host.conf` 一致): + +| 服务 | 本机地址 | +|------|----------| +| API | `127.0.0.1:8088` | +| 前台静态 | `127.0.0.1:9080` | +| 后台静态 | `127.0.0.1:9081` | + +5. **若仍要用容器里的 yh_nginx**(旧方案):`docker compose --profile compose-internal-nginx up -d`,此时会与宿主机抢 **443**,二选一。 + +6. **与「方式 B(8443)」的区别**:方式 B 是「宿主机 Nginx → 容器 Nginx → 各服务」两层;本节是「宿主机 Nginx → 各服务」**一层**,不再起 `yh_nginx`。 diff --git a/nginx/yuheng.host.conf b/nginx/yuheng.host.conf new file mode 100644 index 0000000..09ff803 --- /dev/null +++ b/nginx/yuheng.host.conf @@ -0,0 +1,105 @@ +# 宿主机 Nginx 单实例:443 终止 TLS,反代到本机回环上的 Docker 服务(见 docker-compose.host-nginx.yml) +# 部署: +# 1. 证书:/etc/ssl/yh_web/yuheng.yuxindazhineng.com/{fullchain.pem,privkey.pem} +# 2. 替换下方 __VERIFY_ROOT__ 为项目内 verify-root 的绝对路径(或由 start-with-host-nginx.sh 生成 .conf) +# 3. sudo cp yuheng.host.conf /etc/nginx/conf.d/yuheng.yuxindazhineng.com.conf +# 4. sudo nginx -t && sudo systemctl reload nginx + +# HTTP → HTTPS +server { + listen 80; + listen [::]:80; + server_name yuheng.yuxindazhineng.com; + return 301 https://$server_name$request_uri; +} + +upstream yh_admin_upstream { + server 127.0.0.1:9081; + keepalive 8; +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name yuheng.yuxindazhineng.com; + client_max_body_size 800m; + + ssl_certificate /etc/ssl/yh_web/yuheng.yuxindazhineng.com/fullchain.pem; + ssl_certificate_key /etc/ssl/yh_web/yuheng.yuxindazhineng.com/privkey.pem; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; + + # 域名/证书等验证文件(与 compose 内 yh_nginx 行为一致) + location ~ ^/[A-Za-z0-9._-]+\.(txt|html|xml)$ { + root __VERIFY_ROOT__; + try_files $uri =404; + default_type text/plain; + add_header Cache-Control "no-store"; + } + + location = /admin { + return 301 /admin/; + } + + location /api/web/live/ws { + proxy_pass http://127.0.0.1:8088; + proxy_http_version 1.1; + 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_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + } + + location /api/web/live/danmaku/ws { + proxy_pass http://127.0.0.1:8088; + proxy_http_version 1.1; + 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_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + } + + location /api/ { + proxy_pass http://127.0.0.1:8088; + proxy_http_version 1.1; + 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_set_header X-Forwarded-Proto $scheme; + proxy_connect_timeout 75s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + proxy_buffering off; + } + + location /admin/ { + proxy_pass http://yh_admin_upstream/; + proxy_http_version 1.1; + 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_set_header X-Forwarded-Proto $scheme; + } + + location / { + proxy_pass http://127.0.0.1:9080; + proxy_http_version 1.1; + 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_set_header X-Forwarded-Proto $scheme; + proxy_connect_timeout 75s; + proxy_send_timeout 75s; + proxy_read_timeout 75s; + } +} diff --git a/scripts/start-with-host-nginx.sh b/scripts/start-with-host-nginx.sh new file mode 100644 index 0000000..35d3caa --- /dev/null +++ b/scripts/start-with-host-nginx.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# 宿主机 Nginx 单实例部署:启动 api/web/admin/mongo(不启动容器 yh_nginx),并可选安装站点配置后 reload。 +# 用法(在项目根目录): +# chmod +x scripts/start-with-host-nginx.sh +# ./scripts/start-with-host-nginx.sh +# +# 依赖:已安装 Docker Compose、宿主机 Nginx、证书目录 /etc/ssl/yh_web/yuheng.yuxindazhineng.com/ + +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +echo "==> 启动容器:mongo api web admin(不启动 compose 内 yh_nginx)" +docker compose -f docker-compose.yml -f docker-compose.host-nginx.yml up -d mongo api web admin + +echo "==> 若曾用旧方案启动过 yh_nginx,可手动停止释放 443: docker rm -f yh_nginx 2>/dev/null || true" +docker rm -f yh_nginx 2>/dev/null || true + +VERIFY_ROOT="${VERIFY_ROOT:-$ROOT/verify-root}" +mkdir -p "$VERIFY_ROOT" + +CONF_OUT="${NGINX_CONF_OUT:-/etc/nginx/conf.d/yuheng.yuxindazhineng.com.conf}" +TEMPLATE="$ROOT/nginx/yuheng.host.conf" + +if [[ ! -f "$TEMPLATE" ]]; then + echo "缺少模板:$TEMPLATE" >&2 + exit 1 +fi + +echo "==> 生成宿主机 Nginx 配置(VERIFY_ROOT=$VERIFY_ROOT)" +if [[ "${INSTALL_NGINX_CONF:-1}" == "1" ]]; then + if ! command -v sudo >/dev/null 2>&1; then + echo "未找到 sudo,请手动执行:" >&2 + echo " sed \"s|__VERIFY_ROOT__|$VERIFY_ROOT|g\" \"$TEMPLATE\" | sudo tee \"$CONF_OUT\"" >&2 + echo " sudo nginx -t && sudo systemctl reload nginx" >&2 + exit 0 + fi + sed "s|__VERIFY_ROOT__|$VERIFY_ROOT|g" "$TEMPLATE" | sudo tee "$CONF_OUT" >/dev/null + sudo nginx -t + sudo systemctl reload nginx + echo "==> 已写入 $CONF_OUT 并重载 Nginx。请确认 443 仅由宿主机占用: ss -tlnp | grep 443" +else + echo "已跳过安装(INSTALL_NGINX_CONF=0)。可手动:" + echo " sed \"s|__VERIFY_ROOT__|$VERIFY_ROOT|g\" nginx/yuheng.host.conf | sudo tee $CONF_OUT" + echo " sudo nginx -t && sudo systemctl reload nginx" +fi + +echo "==> 本机回环端口(宿主机 Nginx 应反代到这些地址,与 nginx/yuheng.host.conf 一致):" +echo " API http://127.0.0.1:8088" +echo " 前台 http://127.0.0.1:9080" +echo " 后台 http://127.0.0.1:9081"