单元五 Docker 发布与部署 · 第 22 课
上线前检查
一旦开放到公网,任何人都能访问你的网站,每点一次都在花你的钱。上线之前,先把门锁好、把开销限住。
本课目标
- 让 AI 给周报助手加上访问密码和每日调用上限。
- 完整走一遍“改代码、构建、推送、部署”的发布流程,发布 v2。
- 按清单检查端口、密钥和文件权限。
先懂概念:公网上的风险
互联网上有大量程序在不停地扫描所有 IP 和域名。周报助手一旦能从公网访问,就会遇到:
- 陌生人随手打开、反复点按钮,每一次都在消耗你的 API 额度;
- 程序扫描你的服务,寻找漏洞。
两道最基本的防线:
- 访问密码:不知道密码的人进不来。
- 每日上限:就算密码泄露,也能限制每天调用 AI 的次数。计数保存在内存里,服务重启或更新后会清零,所以它只是一道临时防线,不是费用的硬上限,花费还要在账户后台关注。
跟着做
1. 让 AI 加上防护(在自己电脑上)
cd ~/ai-course/weekly-report
codex上线前请给周报助手加两道防护:
1. 访问密码:从环境变量 APP_USER 和 APP_PASSWORD 读取。设置了 APP_PASSWORD 才开启;开启后所有页面和接口都要求 HTTP Basic 认证,/healthz 除外。比较用户名和密码时使用防时序攻击的比较方式。
2. 每日上限:从环境变量 DAILY_LIMIT 读取,默认 100。每天调用 AI 的次数超过上限后,改用规则版,并提示“今天的 AI 次数已用完,已使用规则版”。计数保存在内存里即可。
同时确认:输入长度限制和超时仍然有效,日志里不打印工作记录和密码。
先说计划,确认后再改。2. 在本地测试
在一个新终端里临时设置密码,启动:
cd ~/ai-course/weekly-report
$env:APP_USER = "me"
$env:APP_PASSWORD = "test-password"
$env:DAILY_LIMIT = "1"
npm startcd ~/ai-course/weekly-report
APP_USER=me APP_PASSWORD=test-password DAILY_LIMIT=1 npm start打开 http://localhost:3000,浏览器会弹出登录框。输入错误的密码进不去,输入 me 和 test-password 才能进入。
这次把每日上限设成了 1:连续生成两次,第一次是 AI 写的,第二次应该提示“今天的 AI 次数已用完,已使用规则版”。确认后停止服务器、关掉这个终端,回到项目文件夹存档:
git add -A
git commit -m "访问密码和每日上限"3. 发布 v2
这就是以后每次发布新版本的流程,第 25 课会整理成清单。
传到服务器(在自己电脑上):
scp -r "$HOME\ai-course\weekly-report" ai-server:scp -r ~/ai-course/weekly-report ai-server:构建并推送(在服务器上):
ssh ai-server看到服务器的提示符后,再运行:
cd ~/weekly-report
docker build -t 你的用户名/weekly-report:v2 .
docker push 你的用户名/weekly-report:v2这次直接用带用户名的全名构建,省去 docker tag 这一步。
在 .env 里加上密码和上限:
cd ~/apps/weekly-report
openssl rand -base64 18openssl rand 会生成一串随机字符,拿它当密码。用 vim .env 在文件末尾加三行:
APP_USER=me
APP_PASSWORD=刚才生成的随机密码
DAILY_LIMIT=100同样不要有空格和引号。把这个密码记到你的密码管理器里。
改用 v2 并重启:用 vim compose.yaml 把 image 那一行末尾的 v1 改成 v2,保存后运行:
docker compose up -d
docker compose psCompose 发现镜像变了,会用新镜像重建容器。
4. 验证
建立隧道(ssh -L 3000:127.0.0.1:3000 ai-server),打开 http://localhost:3000,应该先弹出登录框,输入 .env 里的用户名和密码后才能使用。
上线前检查清单
逐项检查,全部通过再进入下一单元:
| 检查项 | 怎么检查 | 应该看到 |
|---|---|---|
| 防火墙只开 22 端口 | 云服务商控制台的防火墙页面 | 只有 TCP 22 |
| 3000 端口只对本机开放 | 服务器上运行 sudo ss -tlnp | grep 3000 | 127.0.0.1:3000,而不是 0.0.0.0:3000 |
.env 只有自己能读 | ls -l ~/apps/weekly-report/.env | -rw------- |
| 镜像里没有 Key | 把第 19 课“确认 Key 不在镜像里”的两条命令中的镜像名换成 你的用户名/weekly-report:v2 再运行一遍 | 两次都输出 0 |
| 代码里没有 Key | 在自己电脑的项目里运行 git grep --untracked -l "sk-" | 没有真正的 Key |
| 访问密码已开启 | 通过隧道打开网页 | 弹出登录框 |
| 密码足够长 | 看 .env 里的 APP_PASSWORD | 随机生成,16 位以上 |
最后,登录本站的账户后台,看看用量统计,了解周报助手每次调用大概花多少钱。
访问密码使用的是 HTTP Basic 认证,在没有加密的
http://连接上,密码是明文传输的。所以现在只通过 SSH 隧道访问;下一单元配好 HTTPS 以后,才正式对外开放。
常见问题
改了 .env,密码没生效? .env 只在容器创建时读取。改完运行 docker compose up -d,Compose 发现配置变了会重建容器;如果没有重建,运行 docker compose up -d --force-recreate。
登录框一直弹出,输入正确也进不去? 检查 .env 里等号两边有没有多余的空格,用户名和密码是否和你输入的完全一致,大小写也要一样。
网页还是 v1 的样子? 确认 compose.yaml 里改成了 v2,并且运行了 docker compose up -d;docker compose ps 的 IMAGE 一列会显示当前使用的镜像。
自检
- 周报助手要输入密码才能使用。
- 我完整走了一遍发布流程,服务器上运行的是 v2。
- 上线前检查清单全部通过。
- 我知道为什么在配好 HTTPS 之前只通过隧道访问。