Flask 笔记十四:用 Gunicorn 部署 Flask 应用

上一篇我们加了 JSON API,本地用 python manage.pyflask run 就能跑。自己开发没问题,但 不能直接把这套方式原封不动丢到公网服务器。

这一篇做一件事:用 Gunicorn 把 Flask 应用跑成「生产模式」,并知道 Nginx 大概怎么接在前面。

例子仍是通用的 Note 备忘录项目,不涉及任何真实业务。


1. 学完后你能做什么

  • 说清楚 app.run() 和 Gunicorn 的区别
  • 用一条命令启动:gunicorn -w 4 -b 127.0.0.1:5000 app:app
  • 知道 worker 数量 怎么估
  • 上线前检查 FLASK_DEBUG=0、SECRET_KEY、数据库
  • 理解 Nginx 反代 在整体架构里干什么
  • 用 systemd 让进程挂了自动拉起(入门版)

2. 为什么开发用的 app.run() 不适合生产

manage.py 里常见写法:

from app import app

if name == "main":

app.run()

Flask 自带的开发服务器:

特点 开发 生产
并发 弱,单进程为主 需要多 worker
安全 有调试便利,不适合暴露公网 要关 DEBUG
稳定性 改代码自动重载 要常驻、崩溃重启
性能 够用 扛不住真实流量

官方文档也写明:不要用 Werkzeug 开发服务器部署生产。

开发:app.run(debug=True) 方便。

上线:换 Gunicorn(或 uWSGI、Waitress 等),Flask 只负责「应用对象」,不管进程模型。


3. Gunicorn 是什么

Gunicorn(Green Unicorn)是 Python 常用的 WSGI HTTP 服务器:

浏览器 / curl

Nginx(可选,443/80)

Gunicorn(多 worker 进程)

Flask app 对象(你的路由、视图)

你写的 @app.route 不用改;换的是 最外层怎么接 HTTP。


4. 安装与第一条启动命令

虚拟环境里:

pip install gunicorn

在项目根目录(有 app/ 包、manage.py 的那层):

先加载第十二篇的环境变量

export FLASK_DEBUG=0

export SECRET_KEY="生产环境随机长字符串"

export DATABASE_URL=...

gunicorn -w 4 -b 127.0.0.1:5000 "app:app"

参数含义:

参数 含义
-w 4 4 个 worker 进程
-b 127.0.0.1:5000 监听本机 5000 端口
app:app 模块 app 里的变量 app(即 app/__init__.py 里的 Flask 实例)

浏览器访问 http://127.0.0.1:5000/notes/(或你的首页路由)应能打开。

app:app 怎么记?

app:app

│ └── Flask 实例的名字(通常也叫 app)

└── Python 包名(app/ 文件夹)

若实例叫 application,就写 app:application


5. worker 数量怎么选

经验公式(CPU 密集型偏少、I/O 多可略多):

workers = 2 × CPU 核数 + 1

例如 2 核 → -w 5 左右。入门项目 2~4 个 往往够用,别一上来开几十个。

每个 worker 是 独立进程,占一份内存。内存紧张时 worker 要减。


6. 上线前配置清单(接第十二篇)

服务器上的环境变量(如 /etc/myapp.env)至少确认:

FLASK_DEBUG=0

SECRET_KEY=一串足够长的随机值

DATABASE_URL=mysql+pymysql://user:pass@127.0.0.1/dbname

或 SQLite:sqlite:////var/www/myapp/instance/app.db

务必关闭调试:

  • FLASK_DEBUG=1 时,错误页可能 泄露代码和变量
  • 部分场景下还有 远程执行风险(视 Flask/Werkzeug 版本而定)

加载方式:

set -a && source /etc/myapp.env && set +a

gunicorn -w 4 -b 127.0.0.1:5000 app:app

HTTPS 站点若用 Session Cookie,还可加:

SESSION_COOKIE_SECURE=1

(仅 HTTPS 下浏览器才带 Cookie。)


7. 数据库迁移别忘了

第七篇用过 Flask-Migrate。部署新版本代码后:

cd /var/www/myapp

source .venv/bin/activate

set -a && source /etc/myapp.env && set +a

export FLASK_APP=app

flask db upgrade

先迁移、再重启 Gunicorn,避免代码要新字段、表还没改。


8. 静态文件怎么办

备忘录项目的 CSS、JS 在 app/static/,Flask 开发时会自动提供。

生产常见两种做法:

方式 说明
Nginx 直接托管 static 快,减轻 Python 压力(推荐)
仍由 Flask/Gunicorn 提供 小项目、流量低可以先这样

Nginx 示例片段(静态走文件,其余走 Gunicorn):

location /static/ {

alias /var/www/myapp/app/static/;

}

location / {

proxy_pass http://127.0.0.1:5000;

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_pass 到 Gunicorn 也能跑;访问量上来再拆 static。


9. 为什么要 Nginx 挡在前面

Gunicorn 监听 127.0.0.1:5000,不直接暴露公网 时:

  • Nginx 处理 80/443、HTTPS 证书
  • 可配 限流、gzip、上传大小
  • 多站点同一台机器时更好管

架构:

用户 → https://notes.example.com

Nginx :443

Gunicorn 127.0.0.1:5000

Flask app

暂时没域名时,可 -b 0.0.0.0:5000 先验证,记得防火墙只开必要端口,不要长期裸奔。


10. 用 systemd 常驻(进程挂了自动起来)

手动 SSH 里跑 Gunicorn,断开 SSH 进程可能就没了。用 systemd 托管:

/etc/systemd/system/myapp.service

Unit

Description=Note Flask (Gunicorn)

After=network.target

Service

User=www-data

Group=www-data

WorkingDirectory=/var/www/myapp

EnvironmentFile=/etc/myapp.env

ExecStart=/var/www/myapp/.venv/bin/gunicorn -w 4 -b 127.0.0.1:5000 app:app

Restart=always

Install

WantedBy=multi-user.target

启用:

sudo systemctl daemon-reload

sudo systemctl enable myapp

sudo systemctl start myapp

sudo systemctl status myapp

改代码后:

git pull

flask db upgrade # 若有表结构变更

sudo systemctl restart myapp


11. 日志与排错

Gunicorn 默认日志在终端。生产可指定文件:

gunicorn -w 4 -b 127.0.0.1:5000 app:app \

--access-logfile /var/log/myapp/access.log \

--error-logfile /var/log/myapp/error.log

常见问题:

现象 可能原因
502 Bad Gateway Gunicorn 没起来、端口不对
静态 404 Nginx alias 路径错
改代码不生效 没 restart systemd
数据库连不上 DATABASE_URL、MySQL 权限、防火墙
Session 登录丢 SECRET_KEY 变了、Cookie Secure 与 HTTP 混用

12. 开发 vs 生产对照

本地开发 生产
启动 python manage.py / flask run gunicorn app:app
DEBUG 可开 必须关
进程 1 个 多 worker
端口 5000 本机 127.0.0.1 + Nginx
配置 .env /etc/myapp.env
迁移 随手 flask db upgrade 部署流程里固定一步

13. 新手常踩的 5 个坑

  1. 生产仍用 app.run(debug=True) --- 换 Gunicorn,关 DEBUG。
  2. gunicorn manage:appapp:app 混用 --- 以你项目里 Flask 实例在哪定义 为准;常见是 from app import appapp:app
  3. 没做 flask db upgrade 就重启 --- 新代码访问新字段会 500。
  4. SECRET_KEY 每次部署随机变 --- 所有用户 Session 失效;要固定存环境变量。
  5. worker 开太多 --- 内存爆掉,反而更慢。

14. 小结

记住五件事:

  1. app.run() 只用于开发
  2. 生产用 Gunicorn:gunicorn -w 4 -b 127.0.0.1:5000 app:app
  3. FLASK_DEBUG=0 + 强 SECRET_KEY
  4. 前面加 Nginx 做 HTTPS 和反代(入门可先全量 proxy)
  5. systemd + flask db upgrade 组成最小部署闭环

十四篇下来,你已经走完:写功能 → 分层 → 配置外置 → JSON API → 上线跑起来。