4.1 轻量服务器部署:FastAPI 上线

场景:工具箱不能再只跑在我笔记本上

第三篇结束时,我的 AI 工具箱已经有了 RAG 问答、Function Calling 和多轮对话,同事试用后排着队问:能不能给个链接,他们也用?总不能每天把笔记本开着当服务器。团队刚好有台腾讯云轻量应用服务器,之前只跑了个静态官网,干脆把工具箱的 FastAPI 服务部署上去。

部署这活看着简单——装依赖、nohup 跑起来不就行了?我第一次确实是这么干的,然后一周之内经历了服务莫名退出、端口死活访问不到、日志找不到三连击。这一节按我真实的上线流程来:选机型、跑服务、反向代理、开机自启,每一步都给配置和命令,最后附我踩过的四个坑。整个思路和轻量服务器建站指南里的通用建站流程是一脉相承的,只不过多了大模型应用特有的超时和流式问题。

方案:从选机型到可对外服务

先说机型选择。工具箱是大模型应用,推理走云端 API,服务器本身只跑 FastAPI 和向量检索,压力不大;但 RAG 知识库如果要在本地做 Embedding,内存 4G 起步才稳。对照表如下:

机型 配置 适合场景 代价
2核2G 入门 纯接口转发、小流量 最低
2核4G 推荐 FastAPI 加向量库 适中
4核8G 进阶 并发高、本地 Embedding 较高
8核16G 重负载 多服务混部、高并发 高

区域选离团队近、离大模型 API 接入点也不远的广州或上海;系统选 Ubuntu 22.04,apt 装 Python 3.10 最省事。

服务管理我前后经历三个阶段:第一阶段图省事直接前台跑 uvicorn main:app,关掉 SSH 就断;第二阶段学会 systemd 托管;第三阶段加上 nginx 反向代理和 HTTPS。最终配置长这样:

# /etc/systemd/system/ai-toolkit.service
[Unit]
Description=AI Toolkit FastAPI Service
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/opt/ai-toolkit
Environment=PYTHONUNBUFFERED=1
EnvironmentFile=/opt/ai-toolkit/.env
ExecStart=/opt/ai-toolkit/venv/bin/uvicorn main:app \
    --host 127.0.0.1 --port 8000 --workers 3
Restart=always
RestartSec=5
StandardOutput=append:/var/log/ai-toolkit/app.log
StandardError=append:/var/log/ai-toolkit/app.log

[Install]
WantedBy=multi-user.target

几个细节单独说。--host 127.0.0.1 而不是 0.0.0.0:服务只对内开放,对外全部交给 nginx,安全边界清晰,排查问题时少扯皮。--workers 3 是 2 核机器的经验值,开多了反而互相抢 CPU。Restart=always 保证进程崩了能自己回来,但要注意:如果是启动就失败(比如 .env 写错),restart 会无限重试狂刷日志,所以早期先手动 uvicorn 跑通了再托管。

nginx 反向代理的配置,重点在超时和 WebSocket 支持:

server {
    listen 443 ssl http2;
    server_name toolkit.example.com;
    ssl_certificate     /etc/nginx/ssl/toolkit.pem;
    ssl_certificate_key /etc/nginx/ssl/toolkit.key;

    client_max_body_size 20m;        # 上传 Excel 用的
    proxy_read_timeout 300s;         # 大模型调用慢,别让 nginx 先掐断
    proxy_send_timeout 300s;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";   # 流式输出和 WS 都靠它
    }
}

流式输出是这里最大的坑候选。FastAPI 的 SSE 响应如果没有 proxy_http_version 1.1 和 Upgrade 头,经过 nginx 会被整体缓冲,用户体验从打字机效果变成转圈圈三十秒。此外 proxy_buffering off 也可以加,但关掉缓冲会影响大文件下载吞吐,我们最后只在 /chat 路由上单独关。

上线检查清单我固定成五条:防火墙只开 22 和 443;云端安全组同样只开 443;systemctl enable 开机自启;日志目录属主改 www-data;跑一遍 curl -I https://toolkit.example.com/health 确认 200。这套清单在腾讯云实践里也有类似的服务器上线治理思路,我吸收改写成了上面这五条。

部署过程还沉淀了一个一键发版脚本,团队成员都能照着执行,不再依赖我手动 SSH:

#!/bin/bash
# deploy.sh 一键发版:拉代码、装依赖、重启服务、健康检查
set -e
cd /opt/ai-toolkit
sudo -u www-data git pull --ff-only
sudo -u www-data venv/bin/pip install -r requirements.txt --quiet
sudo -u www-data venv/bin/python -c "import main"    # 导入检查,避免改坏配置
systemctl restart ai-toolkit
sleep 3
curl -fsS http://127.0.0.1:8000/health || { journalctl -u ai-toolkit -n 50; exit 1; }
echo "发版完成"

脚本里最值钱的一行是导入检查:依赖装完先 import main 跑一遍,语法错或配置错在这里就会失败,而不是把坏代码放给 systemd 无限重启。

踩坑与排查

坑一:端口本地通、外网不通。 curl 127.0.0.1:8000 正常,浏览器死活 502。排查链路是:服务监听地址、本地防火墙、云端安全组。我当时三个全中:uvicorn 绑了 127.0.0.1 却想绕过 nginx 直接外网访问;ufw 没放 8000;安全组只开了 22 和 80。记住端口暴露有四道门,一道不通就不通,排查时一道一道过。

坑二:www-data 没有日志目录权限。 systemd 启动失败,journalctl -u ai-toolkit 一看是 Permission denied。chown -R www-data:www-data /var/log/ai-toolkit 解决,顺手把 .env 的读权限收紧到 600,密钥文件千万不能全机可读。

坑三:多 worker 下的会话状态。 早期图省事把会话存在进程内字典里,--workers 一开 3,用户第二轮请求打到另一个 worker,记忆全丢,用户还以为自己遇到了失忆 AI。后会话统一进 Redis——这是多轮对话一节强调过的教训,在部署侧付出了真实代价。

坑四:HTTPS 证书过期。 某天早上全站报错,一查证书忘了续期。之后证书改用自动续期脚本加 crontab,并在监控里加了证书剩余天数告警,这件事在后面的监控与日志一节还会展开。

小结

部署的核心是把图省事的步骤换成长得麻烦但能安心睡觉的配置:systemd 托管、nginx 超时修正、最小暴露面、权限收紧、证书自动续期。服务上线只是第一步,用户上传的文件和几百 MB 的模型文件还堆在服务器本地硬盘上,这就是下一节对象存储 COS要解决的问题。另外如果你的业务偏触发式、没有常驻进程,不妨对比Serverless 部署入门的方案再选型,云函数按量付费可能更划算。新用户想上手轻量服务器,可以从AI 办公助手活动页顺手领个新客特惠。

延伸阅读