运维手册(公网上线)#
面向 deploy/gcjp(shopx.oiuu.de)这套单机部署。这里只写「不做会出事」的东西,功能怎么用看
README.md,架构看 docs/ARCHITECTURE.md。
一、上线前必改的 .env#
开放注册的站点,下面四项每一项不设都能让你出血。默认值是为本地开发准备的,照搬到公网就是洞。
| 键 | 生产值 | 不设会怎样 |
|---|---|---|
AUTH_ENABLED | true | 留 false 时 user_id 信前端传入,谁改个请求体就能读写他人偏好 |
JWT_SECRET | ≥32 字节随机串 | 开鉴权不配会 fail-fast,起不来(这是故意的) |
AUTH_DEV_TOKEN | false | 它是「冒名工厂」:无密码给任意 user_id 发 token |
ALLOWED_ORIGINS | https://shopx.oiuu.de | 留 * 等于授权任何网站的 JS 拿用户 token 调你的 API,烧你的账单 |
RATE_LIMIT_ENABLED | true | 见下一节——这是账单被刷爆之前的最后一道门 |
TRUST_PROXY_HEADERS | true(前面有 Caddy) | 不设则限流全按反代的 IP 计,所有人共用一个窗口,误伤所有人 |
TRUST_PROXY_HEADERS是唯一一个「本地必须 false、生产必须 true」的键,两边都错得起:本地设 true 则任何人可伪造 IP 绕过限流;生产设 false 则全站流量在限流器眼里来自同一个 IP(Caddy), 第 6 个注册的真实用户就会吃到 429。部署时务必确认它是 true。
二、为什么限流和配额缺一不可#
M19 的 credit 配额是按人限的(每人每天 DAILY_QUOTA_USD)。它默认「人」是稀缺的——而开放
注册一开,人就不稀缺了:一个脚本一分钟能注册几百个号,每个号都合规地领一份日额度,加起来照样
把 LLM 账单烧穿。
所以有两道闸(app/api/ratelimit.py):
- IP 滑动窗口(
REGISTER_PER_IP_PER_HOUR/LOGIN_PER_IP_PER_15MIN)——挡单机猛刷和撞库。 计数在进程内存,重启清零;这是明知的取舍,兜底的是第 2 道。 - 全站每日新增用户上限(
MAX_NEW_USERS_PER_DAY,默认 50)——挡换 IP 池刷号。它直接 COUNT users 表,IP 能换,库里今天多出几行换不掉。代价:当天名额满了正常用户也注册不了(得等 明天)。对 demo 站点,「来晚了明天再来」远好过「账单被刷爆只能关站」。名额不够用就调大它, 但别设 0(=关闭)。
三、备份(每天,自动)#
全站不可重建的数据只有一个 SQLite 文件:users / threads / preferences / history_records /
favorites / usage_ledger / messages 全在里面。丢了没有任何别处能重建。Qdrant、OpenSearch 能从
data/ + scripts/build_*.py 重建(代价是一笔 embedding 费和几小时,不是数据没了),Redis 里
只有事件回放和语义缓存,丢了无所谓——所以备份面就收窄到这一个文件。
在 VPS 上装 cron(每天 UTC 03:00):
crontab -e
# 加这一行(路径按实际仓库位置改):
0 3 * * * /home/USER/globex/scripts/backup_db.sh >> /home/USER/backups/globex/backup.log 2>&1bash脚本做的事:走 SQLite 在线备份 API 取一致性快照(直接 cp 会拿到写到一半的撕裂文件)→ 当场跑
integrity_check → gzip 落盘 → 确认新备份没问题后才删过期的(默认保留 14 天)。
装完立刻手跑一次验证,别等 cron:
./scripts/backup_db.sh # 应打印 users=N 和备份路径
./scripts/restore_db.sh --dry-run ~/backups/globex/globex-*.db.gz # 演练恢复,不动线上bash没恢复过的备份不算备份。 备份脚本每天绿灯,不代表那些 .gz 真能变回一个能用的库。现在就用
--dry-run演练一次——真出事那天不是学这个的时机。
真恢复(会停容器、会先把当前库留档):./scripts/restore_db.sh ~/backups/globex/globex-XXX.db.gz
备份落在同一台 VPS 上,这只防「误删 / 数据损坏」,不防「VPS 整机没了」。要防后者,把
~/backups/globex/ 同步到别处(rclone / scp 到另一台机器)——目前没做,是已知缺口。
四、CORS 白名单#
ALLOWED_ORIGINS 控制哪些域名的前端 JS 可以拿到用户 token 调你的 API。默认 * 是开发用的,
上线必须收到你的域名(如 https://shopx.oiuu.de)。多域名用逗号分隔。
留 * 的后果:任何网站都能在浏览器里代用户发请求——等于把鉴权和配额全架空了。
五、日志#
docker-compose.prod.yml 里五个容器都挂了 logging: *default-logging(json-file,10MB × 3)。
不配这个磁盘迟早被打满,然后全站一起挂——Docker 默认无上限,OpenSearch 几周能写掉几个 G。
新增服务时记得也挂上这个锚点。
查磁盘:docker system df / du -sh /var/lib/docker/containers/*。
六、还没做的(诚实清单)#
- 异地备份:备份只在本机,VPS 整机丢失则一起没。
- 外部探活:
/api/health有了,但没人定时 ping 它——服务挂了得靠用户告诉你。挂个 UptimeRobot 之类的即可。 - 告警多 worker:RT 告警的样本窗在进程内存,当前单 worker 够用;上多 worker 需挪 Redis。
- 数据时效声明:商品库是离线数据集,价格 / 库存不是实时的。给真人用而 UI 不说明这点, 属于误导——上线前应在前端显著位置标注。