Files
EchoChat/docs/deployment/meeting-mvp.md
bujinyuan f41e63ba6b docs(phase2e-2): 补齐顶层文档进度同步,Phase 2e-2 会议 MVP 全面切
用户准备开始真实用户测试,此 commit 对"六份文档同步"之外遗漏的上层/入口文档
做二次补齐,保证所有出现阶段状态描述的文档都与 CURRENT_STATUS.md 一致。

补齐范围:
- README.md
  · "MVP 功能规划" 原把 Phase 2 / Phase 3 标记为"待开始",与实际进度严重偏离
  · 整段重写为"开发进度"小节,按 Phase 1 / 2a-d / 2e-1 / 2e-2 分别列出 
    已完成状态与关键交付;2e-3 / Phase 3 / P2 推迟项独立列为"待启动(规划中)"
  · "文档导航"扩展 5 条新入口:Phase 2e 路线图 / 2e-2 设计 / 2e-2 实施 /
    2e-2 代码审查 / 2e-2 验收报告 / 会议 MVP 部署指南
- docs/plans/2026-02-27-echochat-system-design.md(整体系统设计方案)
  · §Phase 2e 行:追加"2e-1  / 2e-2  / 2e-3 📋 待启动"状态徽标
  · §Phase 2e-2:从"📋 设计阶段完成,代码开发待启动"改为
    " 已完成(2026-04-24,Task 0-16 全量落地 + 代码审查 4 P0 + 8 P1 + 7 P2 + 7 Nit 闭环)"
- docs/plans/2026-04-21-phase2e-2-design.md(Phase 2e-2 设计文档)
  · 顶部"状态 / 最后更新"由"📋 设计阶段(待评审后进入代码开发)"切 
  · §一 文档定位的"本文档"行同步切 
- docs/plans/2026-04-24-phase2e-2-task15-ui-polish.plan.md(Task 15 计划)
  · 顶部"状态"由"📋 设计阶段(等待用户 Review)"切 
  · 追加"交付记录"行指向 CURRENT_STATUS.md Task 15/16 交付条目
- docs/deployment/meeting-mvp.md(会议 MVP 部署指南)
  · 顶部元信息追加阶段  标记 + Task 16 追加的 REDIS_PASSWORD × redis.conf
    requirepass 联动校验指引

验证:workspace grep "📋 设计阶段|🚧 代码开发|待开始" 在顶层 README/docs 下
已无遗留进度描述与实际状态冲突(仅 README 新增的"Phase 2e-3 / Phase 3 — 待启动
(规划中)"章节为规划项,符合预期)。

Made-with: Cursor
2026-04-23 17:59:32 +08:00

9.5 KiB
Raw Permalink Blame History

EchoChat 会议 MVP 部署指南

适用阶段Phase 2e-2会议 MVP 已完成) 覆盖形态:本机 Demo零配置+ 公网部署(含 TURN 最后更新2026-04-24Phase 2e-2 Task 16 收官E2E 回归 + 代码审查修复 + 资源生命周期审计;本指南 Task 14 双态部署脚本仍为最新有效版本Task 16 追加 REDIS_PASSWORDredis.conf requirepass 联动校验,详见 Task 16 收官说明

一、双态部署总览

EchoChat 会议 MVP 按 Phase 2e-2 设计决策 D01 采用**"一套代码 + 环境变量切换"** 的双态策略,不做代码分支。

对比项 本机 Demolocal 公网部署public
适用场景 开发调试、同局域网演示 上线、跨公网用户
MEDIASOUP_ANNOUNCED_IP 留空(自动探测) 必填服务器公网 IP 或域名解析 A 记录 IP
TURN_ENABLED false(不起 coturn truecoturn 走 profiles: [public]
防火墙/安全组 无特殊要求 需放通 UDP:40000-40199 + TURN 端口
启动方式 ./scripts/start.sh full ./scripts/deploy-public.sh
关键文件 deploy/.env.local.example deploy/.env.public.example

服务拓扑对比见设计文档 docs/plans/2026-04-21-phase2e-2-design.md §4.3 双态部署拓扑


二、本机 Demo 部署

前置要求Docker Desktop含 Compose V2、Node 20+、Go 1.22+

Step 1复制环境变量文件

cp deploy/.env.local.example deploy/.env

本机模式下无需修改任何字段即可跑通(MEDIASOUP_ANNOUNCED_IP 留空,TURN_ENABLED=false)。

Step 2一键启动全栈

./scripts/start.sh full

这会做以下事情:

  1. docker compose up -d --build 拉起 5 个容器:postgres / redis / minio / go-service / media-server
  2. 等待 media-server healthcheck 通过(最多 180 秒)
  3. 用本地进程启动 frontend5173+ admin3100—— 热更体验更好

启动完成后会打印访问地址:

前台用户端 (H5):   http://localhost:5173
后台管理端:        http://localhost:3100
Go 后端 API:       http://localhost:8085
媒体服务器 (SFU):  http://localhost:3300 (healthz: /healthz)
MinIO 控制台:      http://localhost:9001 (echochat / echochat123456)

Step 3验证

./scripts/status.sh
# 预期全部 ● RUNNING

curl http://localhost:8085/healthz         # Go backend
curl http://localhost:3300/healthz         # media-server
curl http://localhost:3300/readyz          # mediasoup worker 已就绪

停止

./scripts/stop.sh full              # 停止 docker compose 全栈(保留数据卷)
./scripts/stop.sh                   # 仅停应用层(保留所有容器)
./scripts/stop.sh --all             # 含数据库中间件

三、公网部署

前置要求

  • 服务器有公网 IP 或已解析 A 记录的域名
  • Docker 已安装
  • 云安全组/iptables 可由你控制(不能仅有 80/443 的 PaaS

Step 1复制模板并替换所有占位符

cp deploy/.env.public.example deploy/.env
vim deploy/.env

必须替换:所有 _REPLACE_WITH_*_ 占位符(否则 deploy-public.sh 会拒绝启动)。

生成强密码的示例:

openssl rand -hex 32    # JWT_SECRET / MEDIA_INTERNAL_TOKEN
openssl rand -base64 24 # 数据库密码 / TURN 密码

核心字段

字段 示例 说明
MEDIASOUP_ANNOUNCED_IP 203.0.113.42 必填服务器公网 IP不能写 127.0.0.1
TURN_ENABLED true 对称 NAT fallback 必备
TURN_USERNAME / TURN_PASSWORD 自设 避免 TURN 账号被互联网滥用
JWT_SECRET 64 hex 生产必改
MEDIA_INTERNAL_TOKEN 32 hex Go ↔ Node 内部鉴权,必须与 media-server/.env 一致

Step 2放通云安全组 / iptables

本脚本不会自动改防火墙(不同云厂商命令不同),请你提前在云控制台/iptables 放通:

协议 端口 用途
TCP 8085 Go backend API
TCP 5173 前台用户端 H5如单独暴露
UDP 40000-40199 mediasoup RTC 流量
TCP 40000-40199 mediasoup ICE-TCP fallback
UDP 3478 coturn STUN/TURN
TCP 3478 coturn
TCP 5349 coturn TLS
UDP 49160-49200 coturn 中继流量

iptables 示例(仅参考,请结合实际 zone 调整):

# UDP 范围
sudo iptables -I INPUT -p udp --dport 40000:40199 -j ACCEPT
sudo iptables -I INPUT -p udp --dport 49160:49200 -j ACCEPT
# STUN/TURN
sudo iptables -I INPUT -p udp --dport 3478 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 3478 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 5349 -j ACCEPT
# API
sudo iptables -I INPUT -p tcp --dport 8085 -j ACCEPT

Step 3运行部署脚本

./scripts/deploy-public.sh

脚本会按 4 步依次执行:

  1. 校验 .env:占位符、长度、ANNOUNCED_IP 必填、DEPLOY_MODE=public
  2. 本机端口检查TCP:8085 / TCP:3300 / 潜在冲突
  3. Docker 环境docker daemon + compose v2 可访问
  4. 启动TURN_ENABLED=true 时用 --profile public(含 coturn否则跳过

启动完成后会打印访问地址。此时用浏览器访问 http://<ANNOUNCED_IP>:5173(或你放通的端口)即可。

验证

./scripts/status.sh

# 容器级检查
docker compose -f deploy/docker-compose.dev.yml ps
docker logs echochat-media-server | tail -40
docker logs echochat-coturn | tail -20

公网验证要点:

  • 两台不同网络的设备(比如手机 4G + 家里 WiFi分别入会双向能看到对端画面
  • Chrome 调 chrome://webrtc-internalsRemote candidate type —— 对称 NAT 场景能看到 relay 类型,说明 TURN 生效
  • curl http://<ANNOUNCED_IP>:8085/healthz 返回 200

停止

./scripts/stop.sh full
# 等价于docker compose -f deploy/docker-compose.dev.yml --profile public stop

四、常见问题 FAQ

Q1docker compose up 卡在 media-server 构建,报 python3 not foundg++ not found

原因mediasoup 的 C++ worker 需要在构建阶段编译原生代码。media-server/Dockerfile 的 builder 阶段已装 python3 + build-essential若你绕过 Dockerfile 本地构建,需要手动装这些。

# Debian/Ubuntu
sudo apt install python3 build-essential pkg-config
# macOS
brew install python3
xcode-select --install

Q2本机 Demo 下两个浏览器 Tab 都在 127.0.0.1:5173但视频流对端一片黑

检查 1MEDIASOUP_ANNOUNCED_IP 一定不要写 127.0.0.1,留空让 mediasoup 自动探测到局域网 IP 即可。

检查 2浏览器摄像头权限是否授予Chrome 左上角锁图标)。

检查 3docker logs echochat-media-server | grep announcedIp,确认探测到的 IP 在你本机 ifconfig 能看到。

Q3公网部署后用手机4G 网络)加入会议,能看到自己但看不到别人?

典型症状:单向 ICE 候选协商不成功。通常是以下之一:

  1. TURN 没打开 —— 确认 TURN_ENABLED=truedocker ps 里有 echochat-coturn。对称 NAT 用户必走 TURN。
  2. UDP:40000-40199 没放通 —— mediasoup 要在这个范围分配动态 RTC 端口。很多云默认只放 80/443/22。
  3. MEDIASOUP_ANNOUNCED_IP 写错 —— 如果是 NAT 机器且写了内网 IP公网用户拿到的候选地址不可达。

Q4为什么 coturn 用 network_mode: host

TURN 服务器为每个会话动态分配中继端口(--min-port=49160 --max-port=49200Docker 默认 bridge 网络的端口映射会把回包的源端口改写导致客户端收不到流量。host 网络能绕过这个问题,是 coturn 官方推荐做法。

代价coturn 会占用宿主机端口命名空间,请确保 3478 / 5349 / 49160-49200 宿主机无占用。

Q5我有 HTTPS 证书,想把前端端口改成 443

MVP 阶段脚本没封装 HTTPS 反代,建议在 compose 外层加 Nginx或 Caddy作为 TLS 终结。mediasoup 的 RTC 流量本身就走 DTLS 加密,不需要你额外处理。

Caddy 最小示例(独立容器或宿主进程):

yourdomain.com {
  reverse_proxy /api/* localhost:8085
  reverse_proxy /ws localhost:8085
  reverse_proxy * localhost:5173
}

Q6public profile 下 stop.sh full 能停掉 coturn 吗?

能。scripts/stop.sh full 里写了 docker compose --profile public stopprofile 参数确保 coturn 这种默认不暴露的服务也被覆盖。

Q7数据库要备份怎么操作

# 快速备份当前数据库
docker exec echochat-postgres pg_dump -U echochat echochat | gzip > backup-$(date +%F).sql.gz

# 从备份恢复(容器停机时)
gunzip -c backup-2026-04-23.sql.gz | docker exec -i echochat-postgres psql -U echochat -d echochat

pgdata / redisdata / minio_data 三个 volume 的物理位置由 Docker 管理:

docker volume inspect deploy_pgdata

五、相关文档