- Add a NAS-specific frpc template that forwards to tuwen_web:80 over the compose network. - Make docker-compose-Nas.yaml create tuwen_frpc by default instead of relying on Compose profiles, which Container Station may not enable. - Remove host networking from the NAS frpc service so the tunnel works through Docker service DNS. - Update README and Docker docs to explain the NAS frpc behavior and logs command.
8.4 KiB
Docker 化部署
本文档说明如何用 Docker Compose 启动完整系统,以及正式部署前需要替换的配置。第一次安装也可参考 安装与初始设置。
服务组成
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:报告图片、签名、模板图片、视频和关键帧文件。
一键启动
docker compose up -d --build
首次启动时,api 容器会自动执行:
- 等待 PostgreSQL 健康。
prisma migrate deploy,把server/prisma/migrations应用到数据库。prisma db seed,写入默认医院、部门、账号、模板和系统设置。- 启动 NestJS API。
访问地址:
前端 HTTP: http://localhost:4002
前端 HTTPS: https://localhost:4443
API 健康: http://localhost:3002/api/health
查看状态:
docker compose ps
查看日志:
docker compose logs -f api
docker compose logs -f web
docker compose logs -f db
停止服务:
docker compose down
连数据库和上传文件一起清空:
docker compose down -v
威联通 NAS 部署
NAS 部署可使用仓库内的 docker-compose-Nas.yaml:
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 部署时建议设置:
# XXX 生产环境应替换 Session 密钥,并信任 Nginx Proxy Manager/frpc 链路传来的 HTTPS 协议头。
SESSION_SECRET=替换为足够长的随机字符串
SESSION_COOKIE_SECURE=true
TRUST_PROXY=true
CORS_ORIGIN=http://NAS_IP:4002,https://your-domain.example
NAS 上的 frpc 隧道:
# XXX 先编辑 frpc/frpc.nas.toml,替换 serverAddr 和 auth.token。
docker compose -f docker-compose-Nas.yaml up -d --build
docker compose -f docker-compose-Nas.yaml logs -f tuwen_frpc
# XXX NAS 版为了适配 Container Station 图形界面会默认创建 tuwen_frpc,不依赖 Compose profile;如果不需要公网映射,可删除或注释 docker-compose-Nas.yaml 中的 tuwen_frpc 服务。公网正式入口只映射 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 或环境文件中设置:
RUN_DB_MIGRATIONS: "false"
RUN_DB_SEED: "false"
然后手动执行:
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 会生成一个只适合本机演示的自签名证书:
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 -> your-domain.example,推荐流程:
# 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使用your-domain.example。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://your-domain.example/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 证书:替换自签名本机证书。
备份与恢复
数据库备份:
docker compose exec db pg_dump -U surclaw surclaw > surclaw_backup.sql
上传文件备份:
docker run --rm -v surclaw_system_uploads_data:/data -v "$PWD":/backup alpine \
tar czf /backup/uploads_backup.tgz -C /data .
恢复数据库前通常需要停服务或进入维护窗口:
docker compose exec -T db psql -U surclaw -d surclaw < surclaw_backup.sql
常见问题
API 容器一直 unhealthy
查看日志:
docker compose logs -f api
常见原因:
DATABASE_URL密码和POSTGRES_PASSWORD不一致。- 数据库还没健康,等待一段时间或重启 compose。
- migration 失败,需要检查
server/prisma/migrations。
页面能打开但保存失败
检查:
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 都没有被调小。
语音听写提示麦克风不可用
本机演示使用:
https://localhost:4443
局域网 HTTP 访问无法由前端代码绕过浏览器限制,只能配置 HTTPS 或使用 Chrome/Edge 临时演示参数。