文章列表
4 分钟阅读

Python Web 项目部署指南:Gunicorn、Uvicorn、Nginx 和 Docker


系列:Python Web 框架

第 10 / 11 篇

  1. FastAPI 安装与使用指南
  2. FastAPI 进阶使用指南
  3. Django 安装与使用指南
  4. Django 进阶使用指南
  5. Django 与 FastAPI 对比:如何选择合适的 Python Web 框架
  6. Python Web 框架有哪些,怎么选
  7. Flask 安装与使用指南
  8. Django REST Framework 入门:把 Django 做成 API
  9. FastAPI 项目实战:用户登录与 JWT 鉴权
  10. Python Web 项目部署指南:Gunicorn、Uvicorn、Nginx 和 Docker
  11. Python Web 项目结构怎么设计

Python Web 项目写完之后,真正让人头疼的往往不是代码,而是部署。

网上经常能看到一堆名字:Gunicorn、Uvicorn、uWSGI、Nginx、Docker、Supervisor、systemd。刚开始看会很乱,因为它们解决的不是同一个问题。

这篇先把边界讲清楚,再给 Django、Flask、FastAPI 各写一个可落地的部署骨架。

先分清 WSGI 和 ASGI

Python Web 服务和应用之间需要一个协议。

WSGI:老协议,同步为主,Django/Flask 传统部署常用
ASGI:新协议,支持异步、WebSocket,FastAPI/Django async 常用

对应关系大概是:

Django 模板站点 Gunicorn / uWSGI(WSGI)
Flask 小应用 Gunicorn(WSGI)
FastAPI API Uvicorn / Gunicorn + UvicornWorker(ASGI)
Django 异步能力 ASGI 入口 + ASGI Server

注意:Django 同时有 wsgi.pyasgi.py,不是说用了 Django 就只能 WSGI。只是大部分传统 Django 项目仍然按 WSGI 部署。

Nginx 负责什么

Nginx 不负责跑 Python 代码,它一般做这些事:

  • 监听 80/443 端口;
  • 处理 HTTPS;
  • 转发请求到 Python 服务;
  • 托管静态文件;
  • 限制上传体积;
  • 做基础缓存或压缩。

常见结构:

Browser
↓ HTTPS
Nginx
↓ HTTP 本机端口
Gunicorn / Uvicorn
Python Web App

Python 服务通常只监听 127.0.0.1:8000 或容器内部端口,不直接暴露到公网。

Django:Gunicorn + Nginx

安装:

Terminal window
pip install gunicorn

收集静态文件:

Terminal window
python manage.py collectstatic

启动 Gunicorn:

Terminal window
gunicorn mysite.wsgi:application \
--bind 127.0.0.1:8000 \
--workers 3

mysite.wsgi:application 对应 Django 项目里的 mysite/wsgi.py

一个简化的 Nginx 配置:

server {
listen 80;
server_name app.local;
location /static/ {
alias /srv/app/staticfiles/;
}
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;
}
}

Django 里还要注意:

ALLOWED_HOSTS = ["app.local"]
CSRF_TRUSTED_ORIGINS = ["https://app.local"]
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

这部分可以和 Django 安装与使用指南Django REST Framework 入门:把 Django 做成 API 连起来看。

Flask:Gunicorn + 应用工厂

假设 Flask 项目入口是 wsgi.py

from app import create_app
app = create_app()

启动:

Terminal window
gunicorn wsgi:app \
--bind 127.0.0.1:8000 \
--workers 2

Flask 的部署问题通常不是 Gunicorn,而是项目早期没有整理结构。不要把数据库连接、配置、路由都堆在一个全局文件里。先看 Flask 安装与使用指南 里的应用工厂模式,会少踩不少坑。

FastAPI:Uvicorn 或 Gunicorn Worker

开发时:

Terminal window
uvicorn main:app --reload

生产环境不要用 --reload

小项目可以直接:

Terminal window
uvicorn main:app \
--host 127.0.0.1 \
--port 8000 \
--workers 4

也可以用 Gunicorn 管理 worker:

Terminal window
gunicorn main:app \
-k uvicorn.workers.UvicornWorker \
--bind 127.0.0.1:8000 \
--workers 4

FastAPI 的关键是:它是 ASGI 应用,入口通常是 main:app,不是 wsgi:application

如果项目里用了 startup/shutdown 或 lifespan 管理数据库连接,部署时要确认它们能正常执行。可以回看 FastAPI 进阶使用指南

用 systemd 管理进程

不用 Docker 时,systemd 是比较稳的选择。

示例服务:

[Unit]
Description=Python web app
After=network.target
[Service]
WorkingDirectory=/srv/app
Environment="PATH=/srv/app/.venv/bin"
Environment="DJANGO_SETTINGS_MODULE=mysite.settings"
ExecStart=/srv/app/.venv/bin/gunicorn mysite.wsgi:application --bind 127.0.0.1:8000 --workers 3
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

加载并启动:

Terminal window
sudo systemctl daemon-reload
sudo systemctl enable python-web
sudo systemctl start python-web
sudo systemctl status python-web

查看日志:

Terminal window
journalctl -u python-web -f

如果只是临时保持 SSH 任务,可以用 Tmux 入门教程:让 SSH 断线和多任务终端不再中断;但长期服务不要靠 tmux 挂着。

Docker 部署骨架

一个简单 Dockerfile:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "mysite.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]

FastAPI 改成:

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]

docker-compose.yml

services:
web:
build: .
ports:
- "127.0.0.1:8000:8000"
env_file:
- .env
restart: unless-stopped

再用 Nginx 反代到 127.0.0.1:8000

如果你还没熟悉容器,可以先读 Docker 安装与使用教程:从零部署第一个容器服务。部署不是必须上 Docker,但 Docker 能减少“服务器上手工装了一堆东西后来没人敢动”的问题。

常见问题

workers 开多少

没有固定答案。Gunicorn 常见经验值是 CPU 核心数 * 2 + 1,但这只是起点。

如果你的接口主要等数据库和外部 API,worker 可以多一点;如果 CPU 计算重,开太多反而互相抢。

最后还是要看监控和压测。

静态文件谁来处理

开发环境框架可以处理。生产环境建议 Nginx 或对象存储处理。

Django 需要 collectstatic。FastAPI 和 Flask 如果只是少量静态文件,也可以由 Nginx 指向目录。

日志写哪里

容器环境优先输出到 stdout/stderr,让平台收集。

systemd 环境可以直接看 journald。不要在应用里乱写相对路径日志文件,部署后很容易找不到或权限不对。

要不要一开始就 Kubernetes

个人项目、小团队项目不用。先把单机 Nginx + systemd 或 Docker Compose 跑稳。等你真的需要滚动发布、弹性扩容、服务发现,再考虑 Kubernetes。

总结

部署 Python Web 项目时,不要先背工具名,先分清职责:

Gunicorn / Uvicorn:跑 Python 应用
Nginx:反向代理、HTTPS、静态文件
systemd:管理宿主机进程
Docker:封装运行环境
日志和监控:告诉你服务是否还活着

Django 和 Flask 大多走 WSGI,FastAPI 走 ASGI。Nginx 在前面收口,Python 服务在后面专心跑业务。

官方部署细节建议看 Gunicorn 文档Uvicorn 文档Nginx 文档