面试知识库

运维手册(公网上线)#

面向 deploy/gcjp(shopx.oiuu.de)这套单机部署。这里只写「不做会出事」的东西,功能怎么用看 README.md,架构看 docs/ARCHITECTURE.md


一、上线前必改的 .env#

开放注册的站点,下面四项每一项不设都能让你出血。默认值是为本地开发准备的,照搬到公网就是洞。

生产值不设会怎样
AUTH_ENABLEDtrue留 false 时 user_id 信前端传入,谁改个请求体就能读写他人偏好
JWT_SECRET≥32 字节随机串开鉴权不配会 fail-fast,起不来(这是故意的)
AUTH_DEV_TOKENfalse它是「冒名工厂」:无密码给任意 user_id 发 token
ALLOWED_ORIGINShttps://shopx.oiuu.de* 等于授权任何网站的 JS 拿用户 token 调你的 API,烧你的账单
RATE_LIMIT_ENABLEDtrue见下一节——这是账单被刷爆之前的最后一道门
TRUST_PROXY_HEADERStrue(前面有 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):

  1. IP 滑动窗口REGISTER_PER_IP_PER_HOUR / LOGIN_PER_IP_PER_15MIN)——挡单机猛刷和撞库。 计数在进程内存,重启清零;这是明知的取舍,兜底的是第 2 道。
  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>&1
bash

脚本做的事:走 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 不说明这点, 属于误导——上线前应在前端显著位置标注。