小服务器的资源是硬约束:内存 1G,CPU 1 核,带宽按量计费。所有取舍都从这里出发。
一、一个进程装下所有东西
门户和分站跑在同一个 Flask 进程里,而不是给每个子站单独起一个服务。 一套解释器、一份依赖、一份内存开销。常驻内存稳定在 120–160 MB, 剩下的大部分留给系统和 SQLite 的页缓存。
Gunicorn 配 2 个 worker × 2 个线程:worker 数不超过核数,线程用来兜住 阻塞的 I/O(SQLite 读、文件读取)。
二、静态资源不要经过 Python
CSS 由 Nginx 直接从磁盘返回,带 Cache-Control: immutable 和 7 天过期。
Python 进程一次都不用醒。这一条对带宽和 CPU 的节省比任何代码优化都直接。
三、公开页面可以被缓存
公开区不读 session、不写登录态,所以响应可以安全地放在 Nginx 的
proxy_cache 里。缓存有效期 5 分钟,加上 proxy_cache_use_stale,
后端哪怕正在重启,访客看到的还是上一次的页面。
首页命中缓存时,后端消耗是 0。突发流量打过来,压力落在 Nginx 上, 而 Nginx 处理静态响应几乎不花 CPU。
四、限流分两层
- 边缘层:Nginx 的
limit_req按 IP 限速,超了直接 429 或 444, 请求根本进不到 Python - 应用层:公开区和登录接口各有进程内的滑动窗口计数, 作为 Nginx 配置失误时的兜底
应用层的计数在进程内存里,多 worker 时各自独立,所以它是兜底而不是主防线。 真要换多实例部署,这里得换成 Redis。
五、页面要小
整个公开区只有一份 CSS,没有任何外部字体、图标库、分析脚本。 单页 gzip 后通常不到 8 KB。移动网络下打开是秒开的,服务器也不会因为 一个页面被反复请求而喘不上气。
六、能自己跑起来
systemd托管进程,非 root 用户,挂了自动重启- 每天备份两个 SQLite 文件,保留 14 天,备份目录不在 Web 根下
- 日志按天轮转,访问与错误分开
- 防火墙只开 22 / 80 / 443,应用端口只监听 127.0.0.1
这些东西写起来花不了多少时间,但省下的是半夜被告警叫醒的次数。