🚀 拒当 Docker 难民!超轻量 FastAPI + uv + Nginx + Systemd 生产级多项目部署保姆级实战
📌 前言
在如今“万物皆可 Docker”的时代,很多人部署个简单的 FastAPI 后端也习惯套个几百兆的容器镜像。但对于低配云服务器(如 1核2G 内存的入门机型)来说,Docker 守护进程和层层容器的额外内存、CPU 开销往往会让服务器不堪重负。
不用 Docker 难道就无法保证环境隔离和优雅部署了吗?
当然不是!本文将带你完整走通一条纯原生、极速、超轻量的生产级部署方案。我们将使用 Python 界的“速度妖魔” uv 代替传统 pip 解决依赖,用 Linux 原生的 Systemd 进行进程守护,再用 Nginx 进行路径前缀(Prefix)分流,并借助 Cursor/VS Code Remote-SSH 实现可视化远程运维。
整套方案不仅内存占用极低,还能完美支持在一台服务器上无缝混部多个不同的后端项目!
🛠️ 技术栈与工具链
- 操作系统:Ubuntu 22.04 / 24.04 LTS
- 后端框架:FastAPI (Python 3.12+)
- 依赖管理:Astral
uv(性能怪兽,比传统 venv/pip 快数十倍) - 进程守护:Systemd
- 反向代理:Nginx
- 远程工具:Cursor / VS Code (Remote - SSH 插件)
🏗️ 部署架构图
第一阶段:准备工作与环境初始化
1. 更新系统并安装基础依赖
sudo apt update && sudo apt upgrade -y
sudo apt install python3 python3-pip python3-venv mysql-server nginx -y
2. 初始化 MySQL 数据库
进入 MySQL 创建项目专属数据库及用户:
sudo mysql -u root
-- 在 MySQL 交互命令行中执行:
CREATE DATABASE my_fastapi_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'fastapi_user'@'localhost' IDENTIFIED BY '你的强密码';
GRANT ALL PRIVILEGES ON my_fastapi_db.* TO 'fastapi_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
3. 安装 Astral uv 包管理器
uv 是目前最快的 Python 包管理工具,线上更新依赖几乎是瞬时完成。
# 一键安装
curl -LsSf [https://astral.sh/uv/install.sh](https://astral.sh/uv/install.sh) | sh
💡 避坑指南:环境变量未生效?
安装完毕后,如果终端提示 uv: command not found,说明环境变量尚未载入。直接运行以下命令,将 uv 的 bin 路径写入 Shell 配置文件,一劳永逸:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
输入 uv --version 验证,若正确显示版本号,说明准备工作顺利通过!
第二阶段:项目初始化与依赖管理
💥 踩坑一:Git 克隆后权限不足(Permission Denied)
在服务器上克隆代码或同步文件后,有时会遇到类似以下报错:
Failed to create virtual environment ... Permission denied (os error 13)
原因:项目目录的所有权属于 root,而当前登录的 ubuntu 普通用户没有写入权限。 解决办法:一键收回项目文件夹的所有权。
# 将路径替换为你的实际项目路径
sudo chown -R ubuntu:ubuntu /home/ubuntu/myresume_dify
💥 踩坑二:Python 3.12 保护机制(PEP 668)
在现代 Linux 系统中直接运行 pip install -r requirements.txt 会遭遇系统报错:
error: externally-managed-environment. This environment is externally managed...
原因:基于 PEP 668 协议,Ubuntu 锁定了系统全局 Python 环境,防止用户安装第三方包破坏系统组件。 解决办法:使用 uv 创建完全隔离的独立虚拟环境。
cd /home/ubuntu/myresume_dify/backend
# 1. 使用 uv 极速创建虚拟环境(默认文件夹名为 .venv)
uv venv
# 2. 使用 uv 安装项目所需的全部依赖
uv pip install -r requirements.txt
你会惊奇地发现,在 uv 的加持下,几十个依赖包仅用不到 3 秒就全部安全地下载并编译完成了!
第三阶段:使用 Systemd 进行进程守护
如果直接在前台用 uvicorn 启动项目,一旦关闭 SSH 终端窗口,程序就会挂掉。我们需要用 Linux 自带的 systemctl 将项目打包为后台守护服务。
1. 配置 Systemd 服务文件
sudo nano /etc/systemd/system/fastapi.service
💥 踩坑三:Bad message / Bad unit file setting 报错
编辑服务文件时,若无意中将行连接到了一起(如把 [Unit] 和后面的属性写在了同一行),在重启服务时会遭遇以下报错:
Unit fastapi.service failed to load properly ... Bad message
请务必确保分行格式精准无误,直接复制并编辑以下标准模板:
[Unit]
Description=FastAPI myresume_dify Backend
After=network.target
[Service]
User=ubuntu
Type=simple
# 你的后端项目绝对路径(存放 main.py 的目录)
WorkingDirectory=/home/ubuntu/myresume_dify/backend
# 指向 .venv 虚拟环境中的 uvicorn 绝对路径,并传入 --root-path 锁定路由前缀
ExecStart=/home/ubuntu/myresume_dify/backend/.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8188 --workers 4 --root-path /myresume
Restart=always
[Install]
WantedBy=multi-user.target
💡 核心设计:--root-path 的妙用
在一台服务器部署多个项目时,通常需要加前缀区分(如 /myresume)。如果不加 --root-path /myresume 参数,当 Nginx 将请求转发给 FastAPI 时,FastAPI 将无法感知到这个前缀,会导致 Swagger UI 的 openapi.json 报 404 错误。
2. 启动并激活服务
# 刷新 Systemd 配置以识别新服务
sudo systemctl daemon-reload
# 启动 FastAPI 服务
sudo systemctl start fastapi.service
# 设置开机自启
sudo systemctl enable fastapi.service
# 查看运行状态
sudo systemctl status fastapi.service
当看到醒目的绿色 active (running) 并且日志提示 Application startup complete.,说明后端已经成功驻留在系统后台!
第四阶段:使用 Cursor 可视化配置 Nginx 前缀分流
由于 /etc/nginx/ 属于系统高保密目录,普通用户无权直接编辑。在这里,我们将利用 Cursor / VS Code 的 Remote - SSH 插件进行可视化运维。
1. 可视化远程连接
- 在本地 Cursor/VS Code 中,安装
Remote - SSH插件。 - 点击左下角蓝色图标
Connect to Host...,输入ubuntu@你的公网IP进行安全连接。 - 连接成功后,选择
Open Folder,直接定位到服务器的 Nginx 配置目录:/etc/nginx/sites-available。
2. 编辑 default 配置文件
双击打开 default 配置文件,在 server { ... } 块中加入我们的反向代理路由。通过这种方式,我们可以在同一个 80 端口上挂载无数个后端,只需前缀不同即可!
server {
listen 80;
server_name 101.34.8.1; # 替换成你的公网 IP 或域名
# ----------------------------------------------------
# 项目 A:我的简历项目 (转发至 8188 端口)
# ----------------------------------------------------
location /myresume {
proxy_pass [http://127.0.0.1:8188](http://127.0.0.1:8188); # 注意:127.0.0.1 只对内网监听,更安全!
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;
}
# ----------------------------------------------------
# 项目 B:未来的另一个新项目 (比如监听 8200 端口)
# ----------------------------------------------------
location /other-project {
proxy_pass [http://127.0.0.1:8200](http://127.0.0.1:8200);
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;
}
}
💥 踩坑四:文件无法保存(Permission Denied - EACCES)
保存时会弹框报错:permission denied, open '/etc/nginx/sites-available/default'。 极速解决:直接点击 Cursor 右下角弹出的蓝色按钮 Retry as Sudo(以管理员身份重试) ,输入服务器用户密码即可无感保存!
3. 热重启 Nginx
在 Cursor 中直接按下 `Ctrl + `` 打开内置终端,输入:
# 验证 Nginx 配置文件语法是否正确
sudo nginx -t
# 重新加载配置
sudo systemctl restart nginx
第五阶段:公网测试与日常运维
1. 验证公网访问
确保你的云服务器后台(如腾讯云、阿里云控制台)的安全组/防火墙中,放行了 80 端口(常规网页服务端口)。 此时,直接在你的本地浏览器中输入: http://你的服务器公网IP/myresume/docs
当那个经典的蓝绿相间的 Swagger UI API 交互文档界面跃然纸上时,恭喜你,项目部署彻底大功告成!
2. 核心运维工具箱
后端开发和运维往往相伴相生,掌握以下三个指令可以帮你解决 90% 以上的线上问题:
-
查看实时日志(排查 Python 逻辑报错的终极利器):
sudo journalctl -u fastapi.service -n 50 -f -
重启后端服务(每次 git pull 更新代码后运行):
sudo systemctl restart fastapi.service -
下线/彻底删除服务:
sudo systemctl stop fastapi.service sudo systemctl disable fastapi.service sudo rm /etc/systemd/system/fastapi.service sudo systemctl daemon-reload
💡 结语
在这篇文章中,我们没有引入庞大的 Docker,而是基于最原生的 Linux 链路,打通了 FastAPI (uv) -> Systemd -> Nginx -> Cursor 可视化 的全闭环部署架构。 这套方案不仅极度节省云服务器的内存,而且得益于 Nginx 的路径分流设计,未来添加新项目只需在 Nginx 中叠加 location 配置,实现了极强的横向扩展能力。
希望本篇保姆级教程对你有所帮助!如果你在部署中遇到了其他神奇的报错,欢迎在评论区一起交流探讨!