Nginx + Gunicorn/Uvicorn:生产环境下的高性能反向代理配置

📂 所属阶段:第五阶段 — 工程化与部署(实战篇)
🔗 相关章节:Docker 容器化部署 · Pydantic Settings 多环境配置


1. 为什么需要 Nginx?

1.1 直接暴露 Uvicorn 的问题

直接:  客户端 → Uvicorn(单进程,单 worker,无限速)
       问题:并发受限,无 SSL,无静态文件优化

Nginx: 客户端 → Nginx → Uvicorn(多 worker,SSL 终结,限速,静态文件)
       优势:高性能反向代理 + 负载均衡 + 安全保护

1.2 Nginx 的核心作用

功能说明
SSL/TLS 终结处理 HTTPS,Uvicorn 只需跑 HTTP
静态文件高效处理 CSS/JS/图片,释放 Python
负载均衡多 worker 分配请求
请求限制防 DDoS、限速
Gzip 压缩减少传输体积
缓存静态资源缓存

2. Uvicorn 高级运行

2.1 单机多 Worker

# 启动 4 个 worker(推荐:CPU 核心数 × 2 - 1)
uvicorn main:app \
    --host 0.0.0.0 \
    --port 8000 \
    --workers 4 \
    --loop uvloop \
    --http httptools \
    --proxy-headers \
    --forwarded-allow-ips='*'

2.2 Gunicorn + Uvicorn Workers

# 安装
pip install gunicorn[gevent]

# gunicorn.conf.py
import multiprocessing

bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1  # 核心数 × 2 + 1
worker_class = "uvicorn.workers.UvicornWorker"
keepalive = 65
timeout = 30
graceful_timeout = 30
max_requests = 10000
max_requests_jitter = 1000  # 随机打散重启时间
accesslog = "-"
errorlog = "-"
loglevel = "info"

# 启动
gunicorn -c gunicorn.conf.py main:app

3. Nginx 配置

3.1 基础反向代理配置

# /etc/nginx/conf.d/daoman.conf

upstream daoman_api {
    server 127.0.0.1:8000;
    keepalive 32;
}

server {
    listen 80;
    server_name daomanpy.com www.daomanpy.com;

    # HTTP 自动跳转 HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name daomanpy.com www.daomanpy.com;

    # SSL 证书(Let's Encrypt 自动续期)
    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied any;
    gzip_types text/plain text/css application/json application/javascript
               application/xml application/xml+rss text/javascript;

    # 限流(防止 DDoS)
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    # 主 API 代理
    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
        limit_conn addr 10;

        proxy_pass http://daoman_api;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        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_set_header X-Forwarded-Host $host;

        proxy_connect_timeout 60s;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;

        client_max_body_size 10M;
    }

    # 静态文件(直接由 Nginx 提供)
    location /static/ {
        alias /var/www/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # WebSocket(长连接)
    location /ws/ {
        proxy_pass http://daoman_api;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_read_timeout 86400;
    }

    # 健康检查(Nginx 直接响应,不用经过 Python)
    location /health_nginx {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }

    # 文档
    location /docs {
        proxy_pass http://daoman_api;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }

    location /openapi.json {
        proxy_pass http://daoman_api;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

4. Systemd 管理服务

4.1 Uvicorn 服务单元

# /etc/systemd/system/daoman-api.service
[Unit]
Description=Daoman FastAPI Service
After=network.target
Wants=network-online.target
Requires=postgresql.service redis.service

[Service]
Type=notify
User=www-data
Group=www-data
WorkingDirectory=/opt/daoman
Environment="ENV=production"
EnvironmentFile=/opt/daoman/.env

ExecStart=/opt/daoman/venv/bin/gunicorn \
    -c /opt/daoman/gunicorn.conf.py \
    main:app

ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStopSec=5
PrivateTmp=true
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

4.2 服务管理命令

# 重新加载配置
sudo systemctl daemon-reload
sudo systemctl restart daoman-api

# 查看状态和日志
sudo systemctl status daoman-api
sudo journalctl -u daoman-api -f --lines=50

# 开机自启
sudo systemctl enable daoman-api

5. 完整生产部署流程

# 1. 服务器安装 Nginx、PostgreSQL、Redis
sudo apt update && sudo apt install nginx postgresql redis-server

# 2. 配置 PostgreSQL
sudo -u postgres psql
CREATE DATABASE myapp;
CREATE USER appuser WITH ENCRYPTED PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE myapp TO appuser;

# 3. 部署代码
git clone https://github.com/your-repo/daoman-api.git /opt/daoman
cd /opt/daoman
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# 4. 配置环境变量
cp .env.production.example .env
nano .env  # 填写真实密钥和数据库连接

# 5. 初始化数据库
alembic upgrade head

# 6. 配置 Nginx
sudo cp nginx/daoman.conf /etc/nginx/conf.d/
sudo nginx -t  # 测试配置
sudo systemctl reload nginx

# 7. 启动服务
sudo systemctl enable --now daoman-api nginx

# 8. 查看最终效果
curl https://daomanpy.com/health_nginx
curl https://daomanpy.com/docs

6. 小结

生产部署架构:

用户 → Nginx (SSL 终结, 限流, 静态文件) → Uvicorn Workers (Python)

        PostgreSQL ← Redis

💡 记住:Nginx 负责接收所有外部流量,Uvicorn 只需监听本地端口。静态文件交给 Nginx 处理,Python 只处理动态请求。


🔗 扩展阅读