Files
ai-video-fullstack/deploy
Xin Wang fa6693ce46 Enhance setup-certs.sh script with OS-specific installation instructions for mkcert
- Update the script to provide clear installation commands for mkcert on macOS and Ubuntu, improving user guidance for certificate setup.
2026-07-09 22:29:48 +08:00
..

开发 HTTPS 调试部署

语音预览要求麦克风可用,浏览器只在 安全上下文(localhost 或 https)下放行 getUserMedia。本机用 localhost 就够;局域网或远程机器用 IP/域名给别的设备测, 就要走 https。开发环境推荐 nginx 统一做 TLS 入口,前端页面、HTTP API 和 WS 信令都同源。

结构

浏览器 ──https/wss──> nginx :443 (唯一 TLS 入口, mkcert 证书)
                       ├── /ws/    → 后端 :8000  (/ws/voice 信令、/ws/stream 裸流)
                       ├── /api/   → 后端 :8000  (assistants/model-resources/...)
                       ├── /health → 后端 :8000
                       └── /       → 前端 :3000  (Next dev + HMR)

前端页面和信令 ws 同源(同 host 同端口),没有混合内容 / 跨源问题。

路径 A:本机 / 局域网,nginx 直接跑在宿主机

适合 Mac 本机调试,或同一局域网里手机访问电脑 IP。

# 1) 装 mkcert(只需一次)
brew install mkcert nss

# 2) 生成证书(本机 CA + localhost/LAN IP/ai-video.local 的证书)
./deploy/setup-certs.sh

# 3) 起前后端(任选其一)
docker compose up -d            # api:8000 + ui:3030 都发布到 localhost
#   或本地分别 npm run dev / uvicorn app:app --port 8000

# 4) 起 nginx(装一下:brew install nginx)
nginx -c "$(pwd)/deploy/nginx/ai-video.dev.conf" -g 'daemon off;'

# 5) 访问
#   本机:  https://localhost  或  https://ai-video.local
#   局域网:https://<本机IP>   (脚本结尾会打印)

deploy/nginx/ai-video.dev.conf 里的证书路径是本机绝对路径。换目录或换机器时, 把 ssl_certificatessl_certificate_key 改到当前仓库的 deploy/certs/

路径 B:远程开发机,Docker nginx + 宿主机 npm/uvicorn

适合在云主机/远程 Linux 上开发:数据库可以用 Docker,但前端和后端单独跑, 便于热更新和看日志。nginx 跑在 Docker 容器里,通过 host.docker.internal 反代到宿主机上的 3000/8000

1. 准备证书

有域名时推荐使用正式证书,把证书文件放到:

deploy/certs/ai-video.pem
deploy/certs/ai-video-key.pem

只做开发调试也可以用 mkcert。远程机器上把访问用的 IP/域名传给脚本:

./deploy/setup-certs.sh <远程机器公网IP或内网IP> <可选域名>

mkcert 是本地 CA。浏览器所在设备要免警告,需要信任这台远程机器生成的 rootCA.pem;否则可以临时接受浏览器的自签证书警告。

2. 启动数据库并初始化

docker compose up -d postgres
make db-seed

make db-seed 会建表、同步接口定义、写入模型资源和助手示例。模型密钥不放 .env,启动后到前端「组件 / 模型」里把 replace-me 换成真实密钥。

3. 单独启动后端

后端必须监听 0.0.0.0,否则 nginx 容器连不到宿主机端口:

cd backend
cp .env.example .env

# 如果 postgres 用 docker compose,宿主机连库可用 localhost:5432
# backend/.env:
# DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/postgres

uv run --with-requirements requirements.txt \
  uvicorn app:app --host 0.0.0.0 --port 8000 --reload

4. 单独启动前端

前端也监听 0.0.0.0NEXT_PUBLIC_API_BASE_URL 要写浏览器最终访问 nginx 的 https 地址,不要写 :8000:

cd frontend
npm install
NEXT_PUBLIC_API_BASE_URL=https://<远程机器IP或域名> \
  npm run dev -- --hostname 0.0.0.0

5. 启动 Docker nginx

推荐用 compose profile:

docker compose --profile remote-dev up -d nginx-remote-dev

也可以直接 docker run:

docker run --rm --name ai-video-nginx \
  --add-host=host.docker.internal:host-gateway \
  -p 80:80 -p 443:443 \
  -v "$PWD/deploy/nginx/ai-video.remote-dev.conf:/etc/nginx/nginx.conf:ro" \
  -v "$PWD/deploy/certs:/etc/nginx/certs:ro" \
  nginx:alpine

访问:

https://<远程机器IP或域名>

6. 远程语音 / WebRTC 注意事项

  • 云安全组至少放行 80/tcp443/tcp
  • 如果浏览器和后端不在同一内网,WebRTC 媒体链路通常需要 TURN。
  • 启动 coturn:
# 项目根 .env:
# PUBLIC_IP=<远程机器公网IP>
# TURN_SECRET=<和 backend/.env 一致的密钥>

docker compose --profile remote up -d coturn
  • 云安全组放行 3478/tcp3478/udp49152-49200/udp
  • backend/.env 中配置:
TURN_URLS=turn:<远程机器公网IP>:3478?transport=udp,turn:<远程机器公网IP>:3478?transport=tcp
TURN_SECRET=<同上>

前端怎么连后端

前端读环境变量 NEXT_PUBLIC_API_BASE_URL(compose 里已设)。走 nginx 后, 让它指向同源即可,ws 地址由它推导:

NEXT_PUBLIC_API_BASE_URL = https://<访问用的host>      # 同源,不再写 :8000
wsUrl = NEXT_PUBLIC_API_BASE_URL.replace(/^http/, 'ws') + '/ws/voice'

没有反代、直连后端时则是 https://<host>:8000,但那样要给后端单独配证书、 还有跨源,不推荐。统一走 nginx 最干净。

给别的设备免警告

证书是 mkcert 本地 CA 签的,只有装了该 CA 的设备才信任:

mkcert -CAROOT          # 打印 CA 目录,里面的 rootCA.pem 拷到设备并信任

LAN IP 不在证书 SAN 里会报名称不匹配——setup-certs.sh 已自动把探测到的 en0/en1 IP 加进 SAN;换网络换了 IP,重跑脚本即可。

证书不入库

deploy/.gitignore 已忽略 certs/。私钥不要提交。

常见问题

nginx 容器里为什么不用 127.0.0.1?

Docker 容器里的 127.0.0.1 是容器自己,不是宿主机。远程开发路径使用 host.docker.internal,并通过 host-gateway 映射到宿主机。

页面能打开,但 HMR 或语音 WS 断开?

检查 nginx 配置里是否保留了 UpgradeConnection 头,以及 /ws/proxy_read_timeout 3600s。本仓库的两份开发 nginx 配置都已经包含。

API 请求跨域报错?

走 nginx 时前端和后端同源,通常不需要跨源。若你绕过 nginx 直接访问后端, 需要在 backend/.envCORS_ORIGINS 加上前端实际 origin。