Files

222 lines
15 KiB
Markdown
Raw Permalink Normal View History

2026-09-21 17:30:02 +08:00
# 腾讯云双应用部署
## 当前状态与上线前提
目前公网域名 `zhouxing199901.site` 仍由腾讯云 EdgeOne Pages/Makers 托管游戏。
2026-09-18 已创建广州地域的轻量应用服务器,公网 IP 为 `203.195.219.128`,配置为 2 核 2GB、40GB 系统盘、Ubuntu 24.04 Docker 镜像。
已登录确认 Docker 29.6.1、Compose 5.3.1 可用。应用现已部署到服务器 `/home/ubuntu/wolin`。2026-09-19 已开放公网 IP HTTPS 入口 `https://203.195.219.128/`,尚未切换公网域名。
服务器上的 MySQL 使用独立数据卷,已导入 2026-09-18 20:12(北京时间)的本地快照,共 8 张表、46 条记录,逐表行数与 SHA256 校验通过。
2026-09-18 21:13(北京时间)已验证双入口首页、原游戏文件哈希、登录、六模块只读查询、退出与未登录拦截;报告保存在服务器 `artifacts/server-verification.json`。
三个容器已启动,数据库与后端健康检查正常。实测空闲时 MySQL 约 473MiB、后端约 63MiB、网关约 10MiB,系统可用内存约 904MiB;此数据不等于并发压力测试结果。
经用户明确同意,备案资源查询服务角色授权已生效。用户随后于 2026-09-18 22:17(北京时间)手动提交首次备案;最新截图显示处于“腾讯云审核”阶段,尚未备案通过。
广州服务器绑定域名对外上线前,需要完成 ICP 备案;当前使用 IP HTTPS 入口,不切换现有域名解析。
本次不修改原 EdgeOne 项目和域名解析,待新服务器验证完成后才切换。
目标布局:
| 地址 | 内容 | 访问控制 |
| --- | --- | --- |
| `/` | 双入口首页 | 公开 |
| `/blackjack/` | 决战21点,保留当前线上构建 | 公开 |
| `/wolin/` | 沃林学生管理系统 | 管理口令 |
| `/wolin/docs` | 学生系统 API 文档 | 同一管理口令 |
云服务器上 Docker Compose 运行 `gateway`(Caddy HTTPS 入口)、`web`(FastAPI)、`db`(MySQL 8.4)。
MySQL 主机名为 `db`,数据写入 `mysql_data` 命名卷,不再连接 Windows。
只有入口容器映射 80/443,MySQL 3306 和应用 8004 不开放到公网。
本地原配置 `compose.yaml` 保留;云端使用独立 `compose.cloud.yaml`,不要将两者合并启动。
建议小规模使用从腾讯云轻量应用服务器 2 核 4GB、Ubuntu 24.04 LTS 开始,硬盘留足备份空间。
按实际购买页核对地域、带宽、流量、首购和续费价;本次没有代购或产生云资源费用。
中国内地地域的网站开通需满足备案要求,选地域前确认域名备案状态。
参考:[轻量应用服务器](https://cloud.tencent.com/product/lighthouse)、[使用限制](https://cloud.tencent.com/document/product/1207/44376)。
## 保留游戏
`deploy/site/blackjack/index.html` 原样复制当前线上构建首页,根路径 `/_next/static/` 保留所有原资源。
已核对线上首页、原本地构建和迁移副本 SHA256 相同:
`fbfaa144502f611b00ec9cfe4a08ab495e33a9088aaa3e9f21e4e21da9d56d0d`。
原游戏代码与业务规则没有修改。保留 HTTPS 域名后,浏览器 localStorage 的来源范围不因路径改变。
原游戏已有“刷新后累计局数/收益归零”的问题,本次原样保留构建,没有把它作为迁移故障修改。
## 配置和口令
部署档案 `artifacts/wolin-cloud-deployment.tar.gz` 不含数据库数据、`.env`、管理密码或 AI 密钥。
在安装 Docker Engine 和 Compose 插件的服务器上,解包到如 `/opt/wolin`,然后执行:
```bash
cd /opt/wolin
docker pull caddy:2-alpine
python3 scripts/prepare_cloud_env.py
chmod 600 .env.cloud artifacts/cloud-access.txt
```
脚本创建 `.env.cloud`(两组独立随机数据库口令、管理密码 scrypt 哈希和会话签名密钥等)及
`artifacts/cloud-access.txt`(管理员登录口令)。现有文件不覆盖,避免错误轮换数据库密码。
应安全保存登录口令;不把这两个文件提交代码仓库或放入静态目录。
AI 云端配置默认为空。用户选择在服务器自行配置专用密钥,不复用本机密钥。在服务器执行:
```bash
python3 /home/ubuntu/wolin/scripts/configure_cloud_ai.py
```
按提示粘贴专用 DeepSeek API 密钥并回车,输入内容不会回显。工具仅更新 `.env.cloud` 的 `DEEPSEEK_API_KEY`,保留数据库和登录配置,以原子替换方式保存为 600 权限文件。
密钥保存后,需要执行 `sudo docker compose --env-file .env.cloud -f compose.cloud.yaml up -d --no-deps --wait web` 重新创建后端容器,再验证真实 AI 查询。
`DEEPSEEK_MODEL` 目前为 `deepseek-flash`,如账户支持的模型不同,修改服务器 `.env.cloud` 中对应值。
截至 2026-09-19 本次排查,云端仍未配置密钥,等待用户输入;误导性的 PyCharm 专用提示已修正并部署。
当前本地 AI 配置不会自动上传、也不会写入镜像。页面和业务管理不依赖 AI 密钥。
云端配置强制使用新生成的随机数据库口令;原 `database.py` 的本机默认连接设置只用于兼容原开发方式。
管理入口使用普通网页登录,成功后使用 HttpOnly、SameSite=Strict 的签名会话 Cookie,8 小时后过期。
生产环境 Cookie 设置 Secure,仅通过 HTTPS 传输;本机 HTTP 预演使用 `AUTH_COOKIE_SECURE=false`。
认证覆盖学生页面、静态资源、所有业务/AI API 和文档;不依赖浏览器原生 HTTP BasicAuth 弹窗。
工作台右上角可退出登录。数据库健康检查仅返回服务状态,不返回业务信息。
这是一组共享管理员凭据,不等于完整的多用户角色权限系统。
## 数据迁移:本地库 → 服务器库
正式切换前停止业务录入,在本地重新导出一次,避免预演之后的数据遗漏:
```powershell
Set-Location 'D:\python编程\student_management_system'
python scripts/export_database.py
```
输出位于忽略的 `artifacts/migration/`:SQL 文件及校验清单 JSON。
SQL 包含真实业务数据,单独通过 SSH/SCP 上传到服务器的非公开目录,例如 `/opt/wolin/artifacts/migration/`。
不要将迁移文件放进 `deploy/site`,不要上传到公开仓库或 EdgeOne 静态站点。
这个过程只读原库,不删除或修改 Windows MySQL。
服务器上先启动空 MySQL,再导入:
```bash
cd /opt/wolin
docker compose --env-file .env.cloud -f compose.cloud.yaml up -d --wait db
python3 scripts/restore_cloud_database.py artifacts/migration/实际导出文件.sql --env-file .env.cloud
docker compose --env-file .env.cloud -f compose.cloud.yaml up -d --build --wait
```
导入工具先检查 SHA256 和目标空库,已有任何表则拒绝导入;成功后核对每张表的行数。
不要使用 `main.py` 初始化生产库,不要运行 `drop_tables` 或种子数据替代真实迁移。
云端上线后所有新增、修改、删除只写云端 MySQL,不会自动与本地双向同步。
## 验证完成后再切换域名
### 域名切换前的服务器内部验证
生成 `.env.cloud` 后、首次启动前,将以下配置设为:
```dotenv
SITE_ADDRESS=http://localhost
HTTP_BIND=127.0.0.1
HTTP_PORT=18080
HTTPS_PORT=18443
AUTH_COOKIE_SECURE=false
```
保留 `COMPOSE_PROJECT_NAME=wolin-cloud` 和生成的所有口令,再按前文启动数据库、导入快照并启动应用。
此时入口仅监听服务器回环地址,公网不开放学生数据或管理口令;不能直接通过公网 IP 浏览。
需要在本机浏览器查看时,使用自己的 SSH 登录方式建立加密隧道:
```powershell
ssh -N -L 127.0.0.1:18081:127.0.0.1:18080 ubuntu@203.195.219.128
```
随后访问 `http://localhost:18081/`;本机 18081 避开原来使用 18080 的 Docker 预演。
隧道运行期间保留终端。也可以先在服务器内部通过 HTTP 检查健康状态、登录和业务查询。
这是迁移快照预演;正式切换前仍需按前文停止业务录入并迁移最新数据,不能把旧快照当作最终数据。
### 公网 IP 的 HTTPS 入口(已启用)
用户已授权开放公网 IP 访问。2026-09-19 在服务器启用了 `deploy/Caddyfile.ip`,使用 Caddy 2.11.4 自动申请和续期可信 IP 证书。腾讯云防火墙保留原有 TCP 80 规则,新增 TCP 443 规则;未公开数据库或后端端口。
外部实际请求确认 HTTPS 返回 200,证书校验成功;HTTP 返回 308 并跳转到 HTTPS。浏览器已验证首页、游戏页面和学生登录页面。
2026-09-19 10:14(北京时间)HTTPS 登录、Secure/HttpOnly/SameSite Cookie、六模块查询、退出及未认证 401 检查全部通过;报告为服务器 `artifacts/ip-https-verification.json`。记录数仍为学生 7、班级 2、老师 5、顾问 10、成绩 12、就业 6。
变更前配置备份位于服务器 `artifacts/before-ip-20260919T015715Z/`,包含私密环境配置,不能放到公开目录。
服务器保留所有数据库口令、会话密钥和 `COMPOSE_PROJECT_NAME=wolin-cloud`,当前入口配置为:
```dotenv
PUBLIC_IP=203.195.219.128
SITE_ADDRESS=https://203.195.219.128
CADDY_CONFIG_FILE=./deploy/Caddyfile.ip
CORS_ORIGINS=https://203.195.219.128
HTTP_BIND=0.0.0.0
HTTP_PORT=80
HTTPS_PORT=443
AUTH_COOKIE_SECURE=true
```
IP 配置显式使用 Let's Encrypt 的 `shortlived` ACME 证书,并设置 `default_sni` 兼容浏览器直接访问 Docker 网关的 IP。需要 Caddy 2.10.1 或更新版本,保留 `caddy_data` 卷以自动续期;不要用自签名证书替代公网证书校验。
只对外映射网站入口 80/443,MySQL 和后端仍在容器内部网络。HTTP 自动跳转 HTTPS,登录和业务请求通过 HTTPS 传输。
本次已完成服务器配置校验、可信证书申请与外网访问测试。域名解析和原 EdgeOne 游戏保持原状。
IP 与域名是不同的浏览器来源,游戏在原域名下的 localStorage 数据不会自动出现在 IP 地址下。
参考:[Caddy TLS 指令](https://caddyserver.com/docs/caddyfile/directives/tls)、[IP 证书说明](https://letsencrypt.org/2026/01/15/6day-and-ip-general-availability)。
### 正式切换
确认备案后,将 `.env.cloud` 恢复为正式域名、`CADDY_CONFIG_FILE=./deploy/Caddyfile`、`CORS_ORIGINS=https://zhouxing199901.site`、`HTTP_BIND=0.0.0.0`、80/443 端口和 `AUTH_COOKIE_SECURE=true`。
保持 Compose 项目名和数据库卷不变,应用配置通过重新创建 `web`、`gateway` 生效。
1. 在新服务器确认首页、游戏流程、学生页面与六模块查询均正常,未认证请求返回 401。
2. 只放行网站入口 80/443;SSH 22 尽量限制自己的来源。无需开放 3306 或 8004。
3. 保留原 EdgeOne 项目和原 CNAME 记录,保存 DNS 配置用于回退。
4. 将根域名原来指向 EdgeOne 的 CNAME 切换为新服务器公网 IP 的 A 记录,检查有无冲突的 AAAA 记录。
5. 域名解析到新服务器且 80/443 可达后,Caddy 自动申请并续期 HTTPS 证书。
6. 重新验证真实域名的首页、两入口、证书和后台数据后再恢复业务录入。
如切换失败,可恢复原 DNS 记录让游戏继续由 EdgeOne 提供。DNS 传播期间旧、新网站可能同时被访问。
不要在此时删除原 EdgeOne 项目,也不要承诺仅靠 DNS 切换实现绝对零停机。
## 日常维护与备份
```bash
docker compose --env-file .env.cloud -f compose.cloud.yaml ps
docker compose --env-file .env.cloud -f compose.cloud.yaml logs --tail=100 web
docker compose --env-file .env.cloud -f compose.cloud.yaml stop
docker compose --env-file .env.cloud -f compose.cloud.yaml start
```
容器重新创建后数据卷仍在;**不要执行 `docker compose down -v`,它会删除数据库卷**。
数据卷解决容器生命周期内的数据保留,不能替代数据库备份。上线后应定期导出数据库,另存一份到服务器之外。
以下命令从云端导出一致性备份(在 Linux 服务器执行):
```bash
mkdir -p artifacts/backups
umask 077
docker compose --env-file .env.cloud -f compose.cloud.yaml exec -T db sh -c 'MYSQL_PWD="$MYSQL_ROOT_PASSWORD" exec mysqldump -uroot --single-transaction --no-tablespaces --set-gtid-purged=OFF "$MYSQL_DATABASE"' > "artifacts/backups/wolin-$(date +%Y%m%d-%H%M%S).sql"
```
应检查命令退出码和备份文件,并定期在隔离空库验证恢复。不要把生产备份覆盖导回正在使用的数据库。
## 本机部署预演
`.env.preview` 使用独立项目名 `wolin-cloud-preview`,HTTP 只绑定 `127.0.0.1:18080`,HTTPS 预留 18443。
预演 MySQL 是独立容器与独立卷,不修改原 MySQL,也不修改现有 `localhost:8004` 容器。
```powershell
python scripts/prepare_cloud_env.py --preview
docker compose --env-file .env.preview -f compose.cloud.yaml up -d --wait db
python scripts/restore_cloud_database.py artifacts/migration/实际导出文件.sql --env-file .env.preview
docker compose --env-file .env.preview -f compose.cloud.yaml up -d --build --wait
```
预演访问 `http://localhost:18080/`,登录口令保存在本机 `artifacts/preview-access.txt`。
学生系统登录地址为 `http://localhost:18080/wolin/login`,账号为 `admin`。
旧版配置可执行 `python scripts/prepare_cloud_env.py --preview --upgrade-auth` 升级认证,账号密码和数据库口令保留。
升级代码后先构建并重建 web,再重建 gateway,使新网页登录接替旧 BasicAuth。不要先取消旧入口认证再保留无认证旧 web。
此地址仅用于本机验证,不能当作公网部署地址。
2026-09-18 本机预演结果:8 张表、46 条记录已导入独立 MySQL 8.4,逐表行数与文件 SHA256 校验通过。
前端根路径和 `/wolin/` 测试、后端 4 组集成测试、公开入口、游戏构建一致性、私有路由认证、静态资源、API 文档前缀与六模块只读查询均通过。
预演 MySQL 容器重新创建后,数据查询再次通过;原 Windows MySQL 各表行数保持不变。
随后修复应用内浏览器 `ERR_INVALID_AUTH_CREDENTIALS`:将原生 BasicAuth 弹窗替换为网页登录,保留原账号密码。
17 项认证测试通过;容器实测登录、签名 Cookie、六模块查询、退出登录及退出后 API 拦截均通过。
预演的 AI 云端密钥保持为空,未调用外部 AI。当前云服务器同样未配置 AI 密钥;业务管理可用,云端 AI 助手仍需配置后验证。
云服务器内部部署已完成,使用 `wolin-cloud` 项目及独立 MySQL 数据卷。网关只映射 `127.0.0.1:18080` 和 `127.0.0.1:18443`,数据库和后端无公网端口映射。
DNS 切换、真实域名 HTTPS 和公网浏览器验收仍需完成;ICP备案完成前保持现有 EdgeOne 游戏站点不变。
本次默认 PyPI 下载多次出现截断,改用清华镜像后构建成功;服务器如遇相同网络问题,可在 `.env.cloud` 添加:
`PIP_INDEX_URL=https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple`。
保持 HTTPS 与包校验,不使用跳过证书或关闭哈希检查的方式。