# Systemd + Uvicorn + FastAPI 部署


使用 Uvicorn 运行 FastAPI，由 systemd 管理服务的启动、停止和异常重启，NGINX 负责对外提供反向代理。

下面以使用 systemd 的 Ubuntu / Debian 服务器为例，应用目录为 `/home/fastapi-user/fastapi-app`，入口为 `server.py` 中的 `app` 实例。部署已有项目时，需要按实际情况修改路径和入口。

## 设置 FastAPI 应用程序

一般本机开发，远程使用 `git` 拉取代码，并配置环境

##### 原生 python

```shell
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
```

##### UV 管理

```shell
uv sync
```

## 配置 systemd

##### 创建服务文件

```shell
sudo vim /etc/systemd/system/fastapi-app.service
```

添加以下内容：

```ini
[Unit]
Description=FastAPI application served by Uvicorn
After=network.target

[Service]
Type=simple
User=fastapi-user
Group=fastapi-user
WorkingDirectory=/home/fastapi-user/fastapi-app
Environment="PYTHONUNBUFFERED=1"
ExecStart=/home/fastapi-user/fastapi-app/.venv/bin/python -m uvicorn server:app --host 127.0.0.1 --port 8000 --workers 1 --proxy-headers --forwarded-allow-ips=127.0.0.1 --timeout-graceful-shutdown 30
Restart=on-failure
RestartSec=5
KillMode=mixed
TimeoutStopSec=60
StandardOutput=journal
StandardError=journal
SyslogIdentifier=fastapi-app

[Install]
WantedBy=multi-user.target
```

主要配置说明：

- `User`、`Group`：运行应用的用户和用户组。
- `WorkingDirectory`：应用工作目录，`server.py` 位于此目录下。
- `ExecStart`：直接使用虚拟环境中的 Python 启动 Uvicorn，无需执行 `source activate`。
- `Restart=on-failure`：进程异常退出时自动重启；通过 `systemctl stop` 主动停止服务不会触发重启。
- `KillMode=mixed`：停止时先向主进程发送终止信号，让它协调 worker 退出；超时后清理剩余进程。
- `TimeoutStopSec`：systemd 等待服务停止的时间，给 Uvicorn 的优雅退出留出余量。
- `StandardOutput`、`StandardError`：将标准输出和错误输出交给 journal 收集。

systemd 的重启与停止行为可参考 [systemd.service](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html) 和 [systemd.kill](https://www.freedesktop.org/software/systemd/man/latest/systemd.kill.html)。

Uvicorn 参数说明：

- `server:app`：表示导入 `server.py` 中的 `app`；如果入口是 `app/main.py`，通常改为 `app.main:app`。
- `--workers 1`：启动一个工作进程，可根据内存和负载调整。使用多 worker 时，各进程的内存相互独立，应用启动逻辑也会在各 worker 中分别执行。
- `--reload`：生产环境不要加此参数，它与 `--workers` 不能同时使用。
- `--proxy-headers` 配合 `--forwarded-allow-ips=127.0.0.1`：只信任本机代理转发的客户端地址和协议头。

参数含义见 [Uvicorn Settings](https://www.uvicorn.org/settings/)。

##### 启动服务并设置开机启动

```shell
sudo systemctl daemon-reload
sudo systemctl enable --now fastapi-app
sudo systemctl status fastapi-app --no-pager
curl http://127.0.0.1:8000/health
```

`active (running)` 表示服务进程正在运行，还需要通过 HTTP 请求确认应用已经正常提供服务。

##### 查看日志

```shell
# 查看最近 100 行日志
sudo journalctl -u fastapi-app -n 100 --no-pager

# 实时查看日志
sudo journalctl -u fastapi-app -f
```

## NGINX 中的配置

创建站点配置：

```shell
sudo nano /etc/nginx/sites-available/fastapi-app.conf
```

添加以下内容，将 `api.example.com` 替换为实际域名，并将域名解析到服务器：

```nginx
server {
    listen 80;
    server_name api.example.com;

    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 $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
    }
}
```

这里按 NGINX 直接面向客户端的单层代理配置，覆盖客户端传入的 `X-Forwarded-For`。如果前面还有 CDN 或负载均衡，需要额外配置可信代理与真实客户端 IP。

启用站点并检查配置，下面的软链接命令只需首次执行：

```shell
sudo ln -s /etc/nginx/sites-available/fastapi-app /etc/nginx/sites-enabled/fastapi-app
sudo nginx -t
```

检查通过后启动 NGINX 并重新加载配置：

```shell
sudo systemctl enable --now nginx
sudo systemctl reload nginx
curl -H 'Host: api.example.com' http://127.0.0.1/health
```

此时可以通过 `http://api.example.com/docs` 访问 FastAPI 的接口文档。服务器安全组或防火墙需要允许 HTTP 的 80 端口；Uvicorn 仅监听本机地址，无需开放 8000 端口。对外正式使用时应进一步配置 HTTPS。

## 更新与维护

##### 更新应用

更新项目代码和依赖时，使用 `fastapi-user` 执行

```shell
sudo -iu fastapi-user
cd /home/fastapi-user/fastapi-app
git pull
exit
sudo systemctl restart fastapi-app
curl http://127.0.0.1:8000/health
```

按实际项目选择依赖安装命令。如果只使用本文的最小示例，修改 `server.py` 后重启服务即可。`restart` 会有短暂服务中断，请求检查若遇到应用尚未启动完成，可以查看日志后重试。

修改 `.service` 文件后，需要重新加载 systemd 配置并重启：

```shell
sudo systemctl daemon-reload
sudo systemctl restart fastapi-app
```

##### 常用管理命令

```shell
sudo systemctl start fastapi-app
sudo systemctl stop fastapi-app
sudo systemctl restart fastapi-app
sudo systemctl status fastapi-app --no-pager

sudo nginx -t
sudo nginx -s reload
```

如果服务启动失败，先通过 `journalctl` 查看错误，重点检查虚拟环境路径、应用入口、文件权限以及端口占用。NGINX 返回 `502` 时，先在服务器执行 `curl http://127.0.0.1:8000/health`，确认后端是否正常，再检查 NGINX 配置和 `/var/log/nginx/error.log`。


---

> 作者: [fupcode](https://github.com/fupcode)  
> URL: https://fupcode.com/blog/posts/devops/systemd-uvicorn-fastapi/  

