Files
2026-09-21 17:30:02 +08:00

222 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 腾讯云双应用部署
## 当前状态与上线前提
目前公网域名 `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 与包校验,不使用跳过证书或关闭哈希检查的方式。