跳到主要内容

5.5 部署上线

本章目标:了解把 FastAPI 项目部署到服务器的完整流程和主流方案。本章偏实操指引,第一次部署建议按「方案 A」一步步来。

1. 开发环境 vs 生产环境

开发生产
启动命令fastapi dev(热重载)fastapi run / uvicorn(多进程,无重载)
数据库SQLiteMySQL / PostgreSQL
密钥配置写死在代码里环境变量
建表create_allAlembic 迁移
入口直接暴露 8000 端口Nginx 反向代理 + HTTPS
文档/docs 开放视情况关闭

2. 第一步:把配置改成环境变量

密钥、数据库地址绝不能写死在代码里(更不能提交 git)。用 pydantic-settings 管理:

pip install pydantic-settings

新建 app/config.py

from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
# 有环境变量用环境变量,没有用默认值(默认值仅供本地开发)
database_url: str = "sqlite:///./blog.db"
secret_key: str = "dev-secret-do-not-use-in-prod"
access_token_expire_minutes: int = 60 * 24
cors_origins: list[str] = ["http://localhost:5173"]

# 也支持从 .env 文件读取
model_config = SettingsConfigDict(env_file=".env")


settings = Settings()

然后把 database.pysecurity.pymain.py 里写死的值改为从 settings 读取,例如:

from app.config import settings

engine = create_engine(settings.database_url, ...)
SECRET_KEY = settings.secret_key

本地开发建一个 .env 文件(加进 .gitignore):

DATABASE_URL=sqlite:///./blog.db
SECRET_KEY=本地随便

生产服务器上则通过真正的环境变量注入:

export DATABASE_URL="mysql+pymysql://bloguser:强密码@localhost:3306/blog"
export SECRET_KEY="$(python -c 'import secrets; print(secrets.token_hex(32))')"

3. 方案 A:Linux 服务器直接部署(最经典)

假设你买了一台 Ubuntu 云服务器:

① 装环境、拉代码

sudo apt update && sudo apt install -y python3.12-venv nginx
git clone https://github.com/you/blog-api.git /opt/blog-api
cd /opt/blog-api
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt

② 准备数据库(以 MySQL 为例)

sudo apt install -y mysql-server
sudo mysql -e "CREATE DATABASE blog CHARACTER SET utf8mb4;
CREATE USER 'bloguser'@'localhost' IDENTIFIED BY '强密码';
GRANT ALL ON blog.* TO 'bloguser'@'localhost';"

pip install pymysql
# 设置好 DATABASE_URL 环境变量后执行迁移
alembic upgrade head

③ 用 systemd 常驻运行

生产启动命令(多进程):

fastapi run app/main.py --workers 4 --port 8000
# 等价于 uvicorn app.main:app --workers 4 --host 0.0.0.0 --port 8000

写成 systemd 服务让它开机自启、崩溃自动拉起。创建 /etc/systemd/system/blog.service

[Unit]
Description=Blog API
After=network.target mysql.service

[Service]
User=www-data
WorkingDirectory=/opt/blog-api
Environment=DATABASE_URL=mysql+pymysql://bloguser:强密码@localhost:3306/blog
Environment=SECRET_KEY=生成的随机密钥
ExecStart=/opt/blog-api/venv/bin/fastapi run app/main.py --workers 4 --port 8000
Restart=always

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now blog
sudo systemctl status blog # 查看状态
journalctl -u blog -f # 看日志

④ Nginx 反向代理 + HTTPS

外网不直接暴露 8000 端口,由 Nginx 转发。创建 /etc/nginx/sites-available/blog

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-Proto $scheme;
}
}
sudo ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

# 免费 HTTPS 证书(域名解析到服务器后执行)
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d api.example.com

至此 https://api.example.com/docs 就能访问了。

4. 方案 B:Docker 部署(团队/多环境推荐)

项目根目录建 Dockerfile

FROM python:3.12-slim

WORKDIR /code
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY ./app ./app
COPY ./alembic ./alembic
COPY alembic.ini .

EXPOSE 8000
CMD ["fastapi", "run", "app/main.py", "--port", "8000"]

配合 docker-compose.yml 一键起「应用 + 数据库」:

services:
db:
image: mysql:8
environment:
MYSQL_DATABASE: blog
MYSQL_USER: bloguser
MYSQL_PASSWORD: 强密码
MYSQL_ROOT_PASSWORD: root强密码
volumes:
- db_data:/var/lib/mysql

api:
build: .
environment:
DATABASE_URL: mysql+pymysql://bloguser:强密码@db:3306/blog
SECRET_KEY: 生成的随机密钥
ports:
- "8000:8000"
depends_on:
- db

volumes:
db_data:
docker compose up -d --build
docker compose exec api alembic upgrade head # 首次跑迁移

5. 方案 C:PaaS 平台(最省事)

不想管服务器,可以用托管平台:Railway、Render、Fly.io 等,连上 GitHub 仓库即可自动部署(通常需要提供 Dockerfile 或启动命令)。国内可看各云厂商的容器/函数服务。适合个人项目和演示。

6. 上线检查清单

  • SECRET_KEY 已换成随机值且来自环境变量
  • 数据库换成 MySQL/PostgreSQL,密码不在代码里
  • echo=True 已关闭;create_all 已移除,用 Alembic
  • CORS allow_origins 只写前端正式域名
  • Nginx + HTTPS 配置完成,8000 端口不对外网开放
  • systemd/Docker 保证进程崩溃自动重启
  • pytest 全绿再部署
  • 兜底异常处理器 + 日志已配置(见错误处理章)

本章小结

  • 配置走环境变量(pydantic-settings),密钥绝不进代码库
  • 经典部署链路:systemd 守护 fastapi run 多进程 → Nginx 反代 → certbot HTTPS
  • Docker Compose 把应用和数据库打包,一条命令起全套
  • 上线前过一遍检查清单

至此教程主线完结!遇到问题时查阅附录:附录 A:常见错误排查