# Docker 化部署 本文档说明如何用 Docker Compose 启动完整系统,以及正式部署前需要替换的配置。第一次安装也可参考 [安装与初始设置](./installation.md)。 ## 服务组成 `docker-compose.yaml` 默认启动三个核心服务,另提供一个可选 frpc 服务: | 服务 | 容器名 | 说明 | 宿主机端口 | | --- | --- | --- | --- | | `web` | `tuwen_web` | Nginx 托管前端静态文件,并代理 `/api` 到后端 | `4002`、`4443` | | `api` | `tuwen_api` | NestJS API、Session、AI/语音代理、文件上传 | `3002` | | `db` | `tuwen_db` | PostgreSQL 16 | `5433` | | `frpc` | `tuwen_frpc` | `# XXX` 可选公网隧道客户端,通过 `--profile frpc` 启用 | 使用 `frpc/frpc.toml` | 持久化 volume: - `postgres_data`:PostgreSQL 数据。 - `uploads_data`:报告图片、签名、模板图片、视频和关键帧文件。 ## 一键启动 ```bash docker compose up -d --build ``` 首次启动时,`api` 容器会自动执行: 1. 等待 PostgreSQL 健康。 2. `prisma migrate deploy`,把 `server/prisma/migrations` 应用到数据库。 3. `prisma db seed`,写入默认医院、部门、账号、模板和系统设置。 4. 启动 NestJS API。 访问地址: ```text 前端 HTTP: http://localhost:4002 前端 HTTPS: https://localhost:4443 API 健康: http://localhost:3002/api/health ``` 查看状态: ```bash docker compose ps ``` 查看日志: ```bash docker compose logs -f api docker compose logs -f web docker compose logs -f db ``` 停止服务: ```bash docker compose down ``` 连数据库和上传文件一起清空: ```bash docker compose down -v ``` ## 威联通 NAS 部署 NAS 部署可使用仓库内的 `docker-compose-Nas.yaml`: ```bash docker compose -f docker-compose-Nas.yaml up -d --build curl http://127.0.0.1:4002/api/health ``` 该配置默认把 PostgreSQL 和上传文件保存到 `/share/Container/tuwen_system_v2/data`,可通过 `NAS_DATA_ROOT` 覆盖。API 诊断端口默认为 `4102`,前端入口仍为 `4002`。 公网 HTTPS 部署时建议设置: ```bash # XXX 生产环境应替换 Session 密钥,并信任 Nginx Proxy Manager/frpc 链路传来的 HTTPS 协议头。 SESSION_SECRET=替换为足够长的随机字符串 SESSION_COOKIE_SECURE=true TRUST_PROXY=true CORS_ORIGIN=http://192.168.31.5:4002,https://sstwbg.example.com ``` 启用 NAS 上的 frpc 隧道: ```bash # XXX 先编辑 frpc/frpc.toml,替换 serverAddr 和 auth.token。 docker compose -f docker-compose-Nas.yaml --profile frpc up -d --build docker compose -f docker-compose-Nas.yaml logs -f frpc ``` `# XXX` 公网正式入口只映射 `4002` 即可;不要把 `4443` 自签名 HTTPS 演示端口映射为公网域名入口。公网 HTTPS 应由 Nginx Proxy Manager 提供。 ## 初始化开关 API 容器启动脚本为 `scripts/docker-api-entrypoint.sh`,可用环境变量控制初始化: | 变量 | 默认值 | 说明 | | --- | --- | --- | | `RUN_DB_MIGRATIONS` | `true` | 启动 API 前执行 `prisma migrate deploy`。 | | `RUN_DB_SEED` | `true` | 启动 API 前执行 `prisma db seed`。当前 seed 使用 upsert,不会清空业务数据。 | | `DOCKER_STARTUP_RETRIES` | `30` | migration/seed 等待重试次数。 | | `DOCKER_STARTUP_RETRY_DELAY` | `2` | 每次重试间隔秒数。 | 如果正式环境希望由运维流水线单独执行 migration,可在 compose 或环境文件中设置: ```yaml RUN_DB_MIGRATIONS: "false" RUN_DB_SEED: "false" ``` 然后手动执行: ```bash docker compose exec api npm run prisma:deploy docker compose exec api npm run prisma:seed ``` ## 端口和代理 - 容器内 API 监听 `3100`,宿主机暴露 `3002`。 - Nginx 对外暴露 `4002` 和 `4443`。 - Nginx 将 `/api/` 反向代理到 `api:3100/api/`。 - `/api/speech/iat` 使用同一条 `/api` 代理路径,并通过 WebSocket upgrade 转发。 - `client_max_body_size 100m` 与后端 `API_BODY_LIMIT=100mb` 对齐,用于图文报告、图片、视频关键帧和 Data URL 上传。 ## HTTPS 和麦克风 Chrome 不允许普通局域网 HTTP 页面调用麦克风。当前 `Dockerfile` 会生成一个只适合本机演示的自签名证书: ```text https://localhost:4443 ``` 如果要用局域网 IP 或域名访问语音听写,应替换 Nginx 证书,并让证书包含实际域名/IP。正式环境建议: - 使用医院内网域名。 - 通过可信 CA 或内网 CA 签发证书。 - 把 `SESSION_COOKIE_SECURE` 设为 `true`。 - 把 `TRUST_PROXY` 设为 `true`。`# XXX` 如果 HTTPS 在 Nginx Proxy Manager、frpc/frps 等外层代理终止,后端需要信任 `X-Forwarded-Proto` 才能正确写入安全 Cookie。 - 把 `CORS_ORIGIN` 改成真实前端 HTTPS 来源。 ## 公网域名反向代理 如果使用 `本机 Docker 4002 -> frpc -> 公网服务器 Nginx Proxy Manager -> sstwbg.example.com`,推荐流程: ```bash # XXX 使用公网 HTTPS 入口时,compose 变量可从 shell 或 .env 覆盖。 export SESSION_SECRET="替换为足够长的随机字符串" export SESSION_COOKIE_SECURE="true" export TRUST_PROXY="true" # XXX 先编辑 frpc/frpc.toml,替换 serverAddr 和 auth.token,再启用 frpc profile。 docker-compose --profile frpc up -d --build docker-compose logs -f frpc ``` Nginx Proxy Manager 配置要点: - `Domain Names` 使用 `sstwbg.example.com`。 - `Forward Hostname / IP` 指向 frpc 在公网服务器暴露的地址。 - `Forward Port` 填 frpc 暴露的端口,例如 `4002`。 - 开启 `Websockets Support`,保证 `/api/speech/iat` 语音听写 WebSocket 可升级。 - SSL 页签绑定证书并开启 `Force SSL`,保证浏览器开放麦克风权限。 - Advanced 中建议设置 `client_max_body_size 100m;`、`proxy_read_timeout 3600s;`、`proxy_send_timeout 3600s;`。 `# XXX` 公网正式访问只映射 `4002` 即可;不要把本机自签名 HTTPS 演示入口 `4443` 直接映射为公网域名入口。公网 HTTPS 应由 Nginx Proxy Manager 负责。 公网验收先访问 `https://sstwbg.example.com/api/health`,再登录并测试报告保存、视频抽帧、AI 对话和语音听写。 ## 生产部署前必须修改 `docker-compose.yaml` 当前适合演示和院内试运行,生产前至少修改: - `POSTGRES_PASSWORD`:替换默认数据库密码。 - `DATABASE_URL`:与新数据库密码保持一致。 - `SESSION_SECRET`:替换为高强度随机值。 - `CORS_ORIGIN`:只保留真实前端来源。 - `SESSION_COOKIE_SECURE`:HTTPS 部署时设为 `true`。 - `TRUST_PROXY`:经反向代理提供 HTTPS 时设为 `true`。 - `RUN_DB_SEED`:不需要每次启动 seed 时可设为 `false`。 - AI/讯飞演示凭据:通过系统设置替换为正式凭据;已经暴露过的密钥应轮换。 - HTTPS 证书:替换自签名本机证书。 ## 备份与恢复 数据库备份: ```bash docker compose exec db pg_dump -U surclaw surclaw > surclaw_backup.sql ``` 上传文件备份: ```bash docker run --rm -v surclaw_system_uploads_data:/data -v "$PWD":/backup alpine \ tar czf /backup/uploads_backup.tgz -C /data . ``` 恢复数据库前通常需要停服务或进入维护窗口: ```bash docker compose exec -T db psql -U surclaw -d surclaw < surclaw_backup.sql ``` ## 常见问题 ### API 容器一直 unhealthy 查看日志: ```bash docker compose logs -f api ``` 常见原因: - `DATABASE_URL` 密码和 `POSTGRES_PASSWORD` 不一致。 - 数据库还没健康,等待一段时间或重启 compose。 - migration 失败,需要检查 `server/prisma/migrations`。 ### 页面能打开但保存失败 检查: ```bash curl http://localhost:4002/api/health curl http://localhost:3002/api/health docker compose logs -f api ``` 如果报告图片或关键帧很大,确认 `API_BODY_LIMIT` 和 Nginx `client_max_body_size` 都没有被调小。 ### 语音听写提示麦克风不可用 本机演示使用: ```text https://localhost:4443 ``` 局域网 HTTP 访问无法由前端代码绕过浏览器限制,只能配置 HTTPS 或使用 Chrome/Edge 临时演示参数。