跳到正文

阿里云公网 Nginx 反向代理与静态托管

本目录只有一个文件:ai-voice-public.conf,是阿里云公网节点 aliyun 上全部公网入口的 Nginx 配置。它同时承担四件事:

  1. HTTPS / WSS 终结:9 个域名共用 wangijun.com 的 Let's Encrypt 通配证书,80 端口整体 301 跳 443;
  2. 前端 SPA 静态托管callflow-webpagecallout-webpagecallai-webpage 三个 Quasar 产物由本机直接发布,不回源、不走隧道;
  3. API 与模型端点反代/api/ 等路径转发到 FRP 回环端口(12008~12013)或本机 callflow-esl9912);
  4. 媒体只读发布:FreeSWITCH 录音目录以 alias 只读暴露。

节点整体职责、部署与更新步骤见上级手册;FRP 回环端口清单见 ../frp/README.md../../wsl-docker/README.md; 跨主机调用矩阵与安全边界见部署网络拓扑与配置


1. server 块总览

域名类型上游 / 根目录
全部 9 个域名(:80跳转return 301 https://$host$request_uri
callflow.wangijun.comSPA + APIroot /usr/app/webpage/callflow-webpage/dist/spa/api/12011/api/auth12012/esl-api/ → 本机 9912
callout.wangijun.comSPA + APIroot /usr/app/webpage/callout-webpage/dist/spa/api/12012
callai.wangijun.comSPA + APIroot /usr/app/webpage/callai-webpage/dist/spa/api/12013/api/auth12012
ai-voice.wangijun.com静态文档站root /usr/app/ai-voice-docs/current
fs.wangijun.comWSS 信令proxy_pass https://172.21.38.245:7443(FreeSWITCH WebRTC profile)
asr.wangijun.comWebSocket回环 12010(WSL sherpa-asr-online-server 20096
tts.wangijun.comHTTP 媒体回环 12008(WSL sherpa-tts-server 29080
emotion.wangijun.comHTTP API回环 12009(WSL emotion-analysis-server 29090
recordings.wangijun.com只读媒体alias /usr/local/freeswitch/var/lib/freeswitch/recordings/

三个 SPA 站点各自还有一个 location = /health,把探活透传到对应后端的 /health,便于用 公网域名直接判断隧道与后端是否在线。


2. 三条必须理解的规则

2.1 前端是本机静态托管,不是隧道回源

SPA 产物直接放在 aliyun 本地磁盘由 Nginx 发布,因此前端更新不需要 FRP、不需要 WSL 在线, 只要 scp 覆盖 dist/spachmod -R a+rX 即可(步骤见上级手册第 3 节)。 FRP 只承载后端 API 与模型端点。

2.2 /api/auth 先于 /api/ 匹配,指向 callout-server

callflow 与 callai 两个站点都把 /api/auth 单独指到 12012(callout-server),其余 /api/ 才走各自后端。这是三端共用一套登录态的实现方式:登录、登出、/auth/me 统一由 callout-server 签发与校验。调整这两个 location 的顺序或前缀会直接导致三端登录互相踢下线

Nginx 的前缀匹配取最长者,/api/auth/api/ 长,所以无论书写顺序如何都优先命中;但为了 可读性,配置里仍把 /api/auth 写在 /api/ 之前,改动时请保持这个约定。

2.3 流式链路必须关缓冲

/api/ 三处反代都设置了:

nginx
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

顶部的 map $http_upgrade $connection_upgrade 是 WebSocket / SSE 升级的前提。这组参数支撑 callai 的 Chat SSE 流式返回、运营监控 SSE 事件流和软电话会话事件流。去掉 proxy_buffering off 会让 SSE 表现为"整通对话结束后才一次性吐字",去掉超时会让长通话的 事件流在默认 60s 后被切断。

fs.wangijun.com 的 WSS 代理超时放宽到 86400s(SIP 注册长连接),且必须 proxy_pass https://…:7443 保持加密上游:降级成 http://…:5066 会让浏览器发出的 Via: WSS 与 Sofia 实际看到的传输不一致,表现为 WSS 握手 101 成功、REGISTER 约 60 秒后 Request Timeout。同时 FreeSWITCH internal profile 的 domains ACL 必须放行 Nginx 的源地址 172.21.38.245/32,改 ACL 后要执行 reloadacl


3. 缓存与安全约定

  • location = /index.html 强制 no-storelocation /assets/immutable + 一年缓存。 Quasar 产物带内容哈希,这样发版后浏览器立刻拿到新 index.html,静态资源仍走强缓存。 前端更新后若页面没变,先确认是不是漏掉了这两条 location。
  • SPA 兜底一律 try_files $uri $uri/ /index.html(hash 路由与刷新直达都依赖它);文档站用 try_files $uri $uri.html $uri/ =404 以支持 VitePress 的 cleanUrls
  • /esl-api/if ($http_token = "") { return 401; },只是挡掉无凭据的探测,不替代 callflow-esl 自身的 http-server.authToken 校验。
  • 录音站点 limit_except GET { deny all; } + autoindex off,只读且不可列目录。
  • 文档站与录音站点都加了 X-Content-Type-Options: nosniff;文档站的 /downloads/ 额外 强制 Content-Disposition: attachment
  • client_max_body_size 20m 决定了号码 CSV/TSV 导入的实际上限——callout-server 侧的限制是 5 MiB,两者不一致时以更小的为准。

4. 与 docs-site/nginx.conf 的关系

ai-voice.wangijun.com 在两个文件里都有 server 块:

  • 本文件内的文档站块;
  • ../docs-site/nginx.conf(按其 README 安装为 /etc/nginx/conf.d/ai-voice-docs.conf)。

两者只能启用其一。同时安装会触发 conflicting server name 警告,Nginx 只保留先加载的那个, 后续改动可能改在不生效的文件上。当前生产以本文件为准;只部署文档站的场景再用 ../docs-site/ 下那份独立配置。


5. 安装与生效

bash
# 1. 上传(本文件是完整配置,不是片段)
scp deploy/aliyun/nginx/ai-voice-public.conf aliyun:/etc/nginx/conf.d/ai-voice-public.conf

# 2. 语法校验后平滑重载,切勿直接 restart
ssh aliyun "sudo nginx -t && sudo systemctl reload nginx"

校准清单(套用到新环境时逐项确认):

当前值说明
域名*.wangijun.com 共 9 个9 个 server_name 加 80 端口跳转块里的列表都要改
证书/etc/letsencrypt/live/wangijun.com/通配证书;include options-ssl-nginx.conf 由 certbot 提供
SPA 根目录/usr/app/webpage/<app>/dist/spaa+rX,属主 aivoice,否则 403/404
文档站根目录/usr/app/ai-voice-docs/current指向 releases/<release-id> 的符号链接
录音目录/usr/local/freeswitch/var/lib/freeswitch/recordings/结尾斜杠不能少(alias 语义)
FreeSWITCH WSShttps://172.21.38.245:7443私网地址,随 FreeSWITCH sip-ip 变化
回环端口12008~12013frpc.tomlremotePort 一一对应

6. 排障速查

现象首查项
SPA 打开 403 / 404chmod -R a+rX /usr/app/webpage/;确认 root 指到 dist/spa 而不是 dist
刷新子路由 404location /try_files … /index.html 兜底是否被改动
发版后仍是旧页面= /index.htmlno-store 是否丢失;浏览器强刷验证
登录后立刻掉线 / 三端互踢/api/auth 是否仍指向 12012
SSE 不逐字返回对应 /api/ 块的 proxy_buffering offmap 块是否完整
长通话事件流 60s 断开proxy_read_timeout / proxy_send_timeout 被恢复成默认值
API 502 / 504先查 FRP:ss -tlnp | grep 120 看回环端口是否在监听,再查 WSL 侧容器
WSS 握手 101 但 REGISTER 超时上游被降级成 http://…:5066;或 FreeSWITCH domains ACL 未放行 172.21.38.245/32
文档站改配置不生效是否与 docs-site/nginx.conf 的同名 server 块冲突(见第 4 节)

更细的软电话媒体侧问题(ICE / TURN / DTLS)见 软电话 WebRTC ICE/TURN 指南全仓排障手册

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。