部署

flask run 启动的开发服务器是单进程、无安全加固的,仅用于开发。生产环境必须使用专业 WSGI 服务器,并在前面放置反向代理。

架构总览

浏览器 → Nginx(TLS、静态文件、限流) → Gunicorn(多 worker) → Flask 应用

选型

  • Gunicorn(Linux 首选):成熟稳定,-w 多进程 + 可选 gevent/gthread 并发模型
  • uWSGI:功能丰富,配置较复杂
  • Waitress:纯 Python、跨平台,Windows 上的主要选择
  • 反向代理:Nginx / Caddy(自动 HTTPS)

Gunicorn

pip install gunicorn

# 4 个 worker 进程,绑定本机 8000 端口
gunicorn -w 4 -b 127.0.0.1:8000 "app:create_app()"

# IO 密集型应用可换 gthread 并发模型
gunicorn -w 4 --threads 8 -k gthread -b 127.0.0.1:8000 "app:create_app()"

worker 数经验值为 CPU 核数 × 2 + 1。绑定 127.0.0.1 而不是 0.0.0.0,只允许本机的 Nginx 访问。

Nginx 反向代理

server {
    listen 443 ssl;
    server_name example.com;

    location /static/ {
        alias /srv/myapp/app/static/;
        expires 30d;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Flask 在代理后需要信任转发头,否则 url_for(..., _external=True) 会生成 http 链接:

from werkzeug.middleware.proxy_fix import ProxyFix

app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)

systemd 守护

# /etc/systemd/system/myapp.service
[Unit]
Description=My Flask App
After=network.target

[Service]
User=www-data
WorkingDirectory=/srv/myapp
Environment="SECRET_KEY=..." "DATABASE_URL=..."
ExecStart=/srv/myapp/.venv/bin/gunicorn -w 4 -b 127.0.0.1:8000 "app:create_app()"
Restart=always

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now myapp

容器化

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:create_app()"]

先复制 requirements.txt 单独安装依赖,可以充分利用 Docker 层缓存。

生产清单

  • DEBUG=FalseSECRET_KEY 来自环境变量且足够随机
  • 数据库连接串、第三方密钥全部通过环境变量注入
  • 配置 ProxyFix 并在 Nginx 设置转发头
  • 静态文件由 Nginx/CDN 服务
  • 日志输出到 stdout(容器)或文件轮转(参见日志章节)
  • 提供健康检查端点(如 GET /healthz 返回 200)
  • HTTPS 强制(HSTS)、会话 Cookie 设置 Secure