# 测试服务器部署方案(国内 ECS · 单机双栈) 日期:2026-09-21 · 目标:把完整系统(cn 管理栈 + ov 观众栈)部署到国内测试 ECS,真实 OSS、可从外网访问、App/浏览器可联调。 服务器画像(已确认):国内阿里云 ECS,已装 1Panel + Docker + MySQL 容器。OSS 凭证已验证(G1 通过)。 **单机双栈说明**:cn 与 ov 两套栈同机部署——ov 的 MySQL 库(photo_ov)也建在同一 1Panel MySQL 实例里,sync 走本机回环连双库,**无需跨境链路**。功能与生产架构完全同构(观众走 ov、管理走 cn、跨境同步本机化),仅地域拆分这一维度被测试环境折叠。 --- ## 0. 前置检查(2 分钟) 在 1Panel 终端执行: ```bash # MySQL 版本必须 ≥ 8.0.30(utf8mb4_0900_bin 校对门槛,需求 §5/D12) docker exec $(docker ps --format '{{.Names}}' | grep -i mysql | head -1) mysql -uroot -p'你的MySQL root密码' -e "SELECT VERSION();" # Redis 是否已装(应用商店装一个即可,记下容器名) docker ps --format '{{.Names}}' | grep -i redis || echo "需要装 Redis(1Panel 应用商店 → Redis,任意版本)" ``` 版本 < 8.0.30 → 先升级 MySQL 容器或改用 utf8mb4_bin(改 infra 迁移脚本四处 CREATE TABLE 的 collation + 重建本地验证,通知我处理)。 ## 1. 本地导出镜像(开发机执行) ```bash cd /d/project/photo TAG=test-20260921 docker build -f docker/server.Dockerfile -t photo-live-server:$TAG . docker build -f docker/web.Dockerfile -t photo-live-web:$TAG . docker save photo-live-server:$TAG photo-live-web:$TAG | gzip > /d/photo-live-$TAG.tar.gz ls -lh /d/photo-live-$TAG.tar.gz # 约 700-900MB(gzip 后) ``` ## 2. 传输与导入 ```bash # 开发机 → 服务器(1Panel 终端也能看 scp 命令;或用宝塔式上传到 /opt) scp /d/photo-live-test-20260921.tar.gz root@<服务器IP>:/opt/ # 服务器上导入 docker load < /opt/photo-live-test-20260921.tar.gz docker images | grep photo-live # 确认两个镜像 ``` ## 3. MySQL 建库授权(1Panel 终端) ```sql -- 1Panel → 数据库 → 终端,或 docker exec 进 MySQL 容器 CREATE DATABASE photo_cn CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin; CREATE DATABASE photo_ov CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin; CREATE USER 'photo'@'%' IDENTIFIED BY '<给 photo 用户设一个强密码>'; GRANT ALL PRIVILEGES ON photo_cn.* TO 'photo'@'%'; GRANT ALL PRIVILEGES ON photo_ov.* TO 'photo'@'%'; FLUSH PRIVILEGES; ``` Redis:1Panel 应用商店装 Redis(无密码即可起步;容器在 1panel-network 网络里,服务经容器名访问)。 ## 4. 目录与 env(服务器执行) ```bash mkdir -p /opt/photo-live && cd /opt/photo-live ``` **`.env.cn`**(关键项;完整清单见仓库 `.env.production.example-cn`——复制后改以下值): ```env # 数据库:容器名取决于 1Panel 实例名(docker ps 查,替换 mysql 的实际容器名) DATABASE_URL_CN=mysql://photo:<上面设的密码>@:3306/photo_cn?connection_limit=10 DATABASE_URL_OV=mysql://photo:<密码>@:3306/photo_ov?connection_limit=10 REDIS_URL_CN=redis://:6379 # OSS(G1 已验证的定案形态) S3_ENDPOINT=https://oss-cn-beijing.aliyuncs.com S3_REGION=oss-cn-beijing S3_ACCESS_KEY=<你的AK> S3_SECRET_KEY=<你的SK> S3_BUCKET=live-album S3_FORCE_PATH_STYLE=false # 同步密钥(生成:openssl rand -hex 32) SYNC_INTERNAL_KEY= OV_API_URL=http://api-cn:8081 # 同机:sync 直连 api-ov 容器 CN_API_URL=http://api-cn:8080 PORT=8080 PORT_OV=8081 # 管理员种子 ADMIN_ACCOUNT=admin ADMIN_PASSWORD=<设一个初始管理员密码> # 测试环境:允许跨源(有正式域名后收窄) CORS_ORIGINS=* ``` **`.env.ov`**:同文件的 OSS 段 + `DATABASE_URL_OV` + `REDIS_URL_OV=redis://:6379` + `PORT_OV=8081`(完整清单见 `.env.production.example-ov`)。 ## 5. 编排启动 把仓库的 `infra/deploy/docker-compose-cn.yml`、`docker-compose-ov.yml` 上传到 `/opt/photo-live/`,然后: ```bash cd /opt/photo-live # 1Panel → 容器 → 编排 → 创建 → 粘贴 compose 内容(界面化路径) # 或命令行(compose 文件里 SERVER_IMAGE/WEB_IMAGE 环境变量指定 tag): SERVER_IMAGE=photo-live-server:test-20260921 WEB_IMAGE=photo-live-web:test-20260921 \ docker compose -f docker-compose-cn.yml up -d SERVER_IMAGE=photo-live-server:test-20260921 WEB_IMAGE=photo-live-web:test-20260921 \ docker compose -f docker-compose-ov.yml up -d ``` compose 默认连接 `1panel-network` 外部网络;若你的网络名不同(`docker network ls` 查),改 compose 尾部 networks 段。 ## 6. 数据库迁移 + 管理员种子(一次性) ```bash docker run --rm --network 1panel-network --env-file .env.cn \ photo-live-server:test-20260921 migrate-deploy all docker run --rm --network 1panel-network --env-file .env.cn \ photo-live-server:test-20260921 seed-admin ``` ## 7. 验证(冒烟四点) ```bash # 服务器上: bash scripts/prod-smoke.sh http://127.0.0.1:8080 http://127.0.0.1:8081 admin '' # 开发机上(外网可达性;先在 ECS 安全组放行 8088/8089): curl http://<服务器IP>:8088/v1/health curl http://<服务器IP>:8089/v1/health ``` 通过标志:四点全 PASS + 两个 health 返回 `{"status":"ok"}`。 ## 8. 访问入口与联调 | 入口 | 地址 | 用途 | |---|---|---| | 观众页(走 ov 栈,真实观众链路) | `http://:8089/a/` | 浏览/点赞/气泡/热门 | | 管理后台(cn 栈) | `http://:8088/admin/` | 全功能后台 | | 观众页(cn 只读形态) | `http://:8088/a/` | 备用 | | App | 构建时 `--dart-define API_BASE=http://:8080` 或装 debug 包后改配置 | 真机联调 | | 嵌入组件 | 宿主页引 `http://:8089/embed/v1/loader.js` | 官网接入形态 | 后续上正式域名:1Panel → 网站 → OpenResty 反代 8088/8089 + 证书,env 的 CORS_ORIGINS 收窄为域名,无需改代码。 ## 9. 安全与运维注意(测试环境基线) - 安全组只放行 8088/8089(web);8080/8081/3306/6379 不对公网开放(web 容器同机反代 /v1)。 - `.env.cn/.env.ov` 权限 `chmod 600`;AK 建议按此前提醒在稳定后轮换。 - 日志:compose 已配 json-file 10m×3;看实时 `docker logs -f photo-api-cn`。 - 回滚:`SERVER_IMAGE` 换回旧 tag `docker compose up -d` 即可(迁移向前兼容原则,详见 RUNBOOK.md)。 --- ## 执行分工(二选一) - **你执行**:按 0→8 逐步粘贴(约 30-40 分钟,大头是镜像传输);卡在任何一步叫我。 - **我执行**:提供 SSH 访问方式(密钥/密码经安全渠道),我在服务器上跑完全部步骤并回报冒烟结果;镜像 tar 我先在本机备好。