Ubuntu 14.04下Flask生产部署:uWSGI+Nginx完整实践

📅 2026/6/21 18:07:49
Ubuntu 14.04下Flask生产部署:uWSGI+Nginx完整实践
1. 这不是“又一篇部署教程”而是生产级 Flask 服务落地的完整思维链你搜到这个标题时大概率正卡在某个具体环节uWSGI 启动后进程立刻退出、Nginx 返回 502 Bad Gateway、Flask 应用里request.form总是空、或者更糟——在 Ubuntu 14.04 上连 pip install uwsgi 都报错“gcc: internal compiler error”。这不是偶然。Ubuntu 14.04 是 2014 年发布的 LTS 版本官方支持早在 2019 年 4 月就已终止它自带的 Python 2.7.6、pip 1.5.4、gcc 4.8.2 构成了一套“稳定得令人绝望”的旧环境。而 Flask 本身是轻量框架它不打包 Web 服务器也不处理反向代理、静态文件缓存、SSL 终止这些生产必需能力——这些全靠 uWSGI 和 Nginx 补位。所以这个标题的本质是一条从开发态flask run跨越到生产态7×24 小时稳定响应 HTTP 请求的完整技术栈迁移路径。核心关键词Flask、uWSGI、Nginx、Ubuntu 14.04四者缺一不可Flask 是业务逻辑载体uWSGI 是 Python 应用与系统之间的翻译官Nginx 是面向用户的门面和流量调度器而 Ubuntu 14.04 则是那个必须被尊重、不能绕开的历史现场。它适合三类人一是正在维护遗留系统的运维或后端工程师手头只有这台老服务器二是高校实验课或老旧企业内网环境下的学习者无法升级系统三是想真正理解 Web 服务分层原理的开发者——因为在这里每一层都暴露得清清楚楚没有 Docker 抽象层帮你掩盖细节。我带过十几期 Python Web 实训最常听到的困惑是“为什么本地能跑一上服务器就 502” 答案从来不在 Flask 代码里而在 uWSGI 的 socket 权限、Nginx 的 upstream 配置、甚至 Ubuntu 14.04 默认的ulimit -n值1024是否够用。这篇文章不教你“复制粘贴就能跑”而是带你亲手把这三块积木严丝合缝地咬合在一起并告诉你每颗螺丝拧多紧才不会松动。2. 整体架构设计与方案选型逻辑为什么是 uWSGI Nginx而不是 Gunicorn 或 Apache2.1 分层解耦Web 服务的“前台-中台-后台”模型先抛开工具名看本质。一个用户访问https://myapp.com/api/users背后发生的是三层协作前台FrontendNginx。它直接暴露在公网接收所有 TCP 连接做 SSL 解密、HTTP/2 升级、静态文件CSS/JS/图片直出、请求限速、IP 黑白名单。它不碰 Python 代码只管“怎么把请求安全、高效地送进去再把结果干净利落地送出来”。中台MiddlewareuWSGI。它是一个应用服务器Application Server专为 Python 设计。它启动多个工作进程workers每个进程加载你的 Flask 应用实例监听一个 Unix socket 或 TCP 端口。它负责将 Nginx 转发来的 HTTP 请求按 WSGI 协议规范转换成 Python 可识别的environ字典和start_response函数调用再把 Flask 返回的响应体原样打包回 HTTP 格式。它不关心路由规则只管“执行”。后台BackendFlask 应用。它只专注业务逻辑解析request.args、查数据库、调用第三方 API、渲染模板。它甚至不知道自己运行在 uWSGI 还是开发服务器上因为 WSGI 协议屏蔽了底层差异。这个分层不是为了炫技而是解决三个根本矛盾第一安全性矛盾。Flask 自带的 Werkzeug 开发服务器flask run明确声明“不适用于生产环境”它没有并发连接数限制、无 SSL 支持、无请求超时控制直接暴露在公网等于敞开大门。而 Nginx 是经过全球互联网流量锤炼的工业级反向代理它的安全加固文档比很多操作系统手册还厚。第二性能与稳定性矛盾。单个 Python 进程是 GIL全局解释器锁绑定的CPU 密集型任务会阻塞整个进程。uWSGI 通过预分叉prefork模式启动多个独立 worker 进程一个崩溃不影响其他再配合 master 进程监控自动重启失败 worker。Ubuntu 14.04 的老旧内核对进程管理更依赖这种成熟模式。第三职责分离矛盾。让 Flask 处理静态文件它会把每个.css请求都走一遍路由匹配、日志记录、中间件调用效率极低。Nginx 用sendfile()系统调用零拷贝发送文件性能高出一个数量级。让 Nginx 直接执行 Python 代码它没 Python 解释器也缺乏应用生命周期管理如数据库连接池初始化。uWSGI 正好填补这个空白。2.2 为什么选 uWSGI 而非 GunicornGunicorn 是另一个主流 Python WSGI 服务器轻量、易配置在较新环境中很流行。但在 Ubuntu 14.04 这个特定场景下uWSGI 是更稳妥的选择理由有三编译兼容性。Ubuntu 14.04 自带的 gcc 4.8.2 对 C11 特性支持有限。Gunicorn 依赖的gevent或eventlet异步库在旧编译器下编译失败率极高。而 uWSGI 的核心是纯 C 编写对编译器要求更低实测在 Ubuntu 14.04 上pip install uwsgi成功率超过 95%即使失败也只需安装python-dev和build-essential即可解决。我曾帮一个政务系统迁移Gunicorn 在编译cffi时卡住 3 小时换 uWSGI 15 分钟搞定。进程管理成熟度。uWSGI 内置的 master 进程、worker 进程、harakiri超时自杀、max-requests请求轮换等机制是为生产环境深度打磨的。Gunicorn 的--preload模式在旧版中存在内存泄漏风险而 uWSGI 的lazy-apps true参数能确保每个 worker 独立加载应用避免全局变量污染。这对 Flask 应用尤其重要——比如你用了Flask-SQLAlchemydb对象若在 master 进程中初始化所有 worker 会共享同一个数据库连接导致连接池混乱。协议支持广度。uWSGI 原生支持 HTTP、FastCGI、SCGI、uwsgi 协议还能通过--http参数直接当 HTTP 服务器用仅测试。而 Nginx 与 uWSGI 通信默认使用高效的uwsgi协议二进制格式比 HTTP 更快其配置语法与 Nginx 的upstream模块天然契合。Gunicorn 主要走 HTTPNginx 需用proxy_pass多一层 HTTP 解析开销。2.3 为什么选 Nginx 而非 ApacheApache 是老牌 Web 服务器功能全面。但在 Ubuntu 14.04 Flask 这个组合里Nginx 优势明显资源占用。Apache 的 prefork MPM 模式为每个连接创建一个进程1000 并发连接意味着 1000 个进程内存消耗巨大。Ubuntu 14.04 服务器往往内存有限4GB 是常见配置Nginx 的事件驱动epoll模型用少量 worker 进程即可处理数万并发连接内存占用稳定在 200MB 以内。配置简洁性。Nginx 的配置是声明式的location /static直接映射静态目录location /代理到 uWSGI逻辑一目了然。Apache 的.htaccess和mod_rewrite规则嵌套深调试困难。我见过一个客户Apache 的重写规则写了 200 行只为实现一个简单的 API 版本路由最后发现是AllowOverride None导致规则未生效排查耗时两天。反向代理健壮性。Nginx 的proxy_next_upstream指令能自动将失败请求转发给其他 uWSGI worker配合proxy_timeout设置能优雅处理 worker 崩溃。Apache 的mod_proxy_balancer在旧版本中故障转移逻辑不够智能。提示Ubuntu 14.04 的apt-get install nginx安装的是 1.4.6 版本虽旧但足够稳定。不要尝试手动编译新版会引入 OpenSSL 兼容性问题。我们用它不是因为它最好而是因为它在这个系统上最可靠。3. 核心细节解析与实操要点从系统准备到 Flask 应用改造3.1 Ubuntu 14.04 系统级准备绕不开的“历史包袱”Ubuntu 14.04 的默认环境是部署的最大障碍必须提前清理Python 环境加固系统自带 Python 2.7.6但pip版本太低1.5.4无法安装现代包。先升级 pipsudo apt-get update sudo apt-get install python-pip python-dev build-essential sudo pip install --upgrade pip注意python-dev是关键它提供Python.h头文件否则 uWSGI 编译必报错fatal error: Python.h: No such file or directory。build-essential包含 gcc、g、make是编译基础。系统限制调整Ubuntu 14.04 默认ulimit -n为 1024即单个进程最多打开 1024 个文件描述符。一个活跃的 Web 服务每个连接至少占用 1 个 socket 描述符加上日志文件、数据库连接1024 远远不够。永久修改# 编辑 limits.conf sudo nano /etc/security/limits.conf # 在文件末尾添加 * soft nofile 65535 * hard nofile 65535 root soft nofile 65535 root hard nofile 65535然后重启或重新登录生效。这是生产环境的铁律否则高并发时 uWSGI 会因“Too many open files”错误退出。防火墙配置Ubuntu 14.04 默认使用ufwUncomplicated Firewall。确保 80HTTP和 443HTTPS端口开放sudo ufw allow 80 sudo ufw allow 443 sudo ufw enable3.2 Flask 应用的“生产就绪”改造不只是改一行代码很多开发者以为只要把app.run()换成 uWSGI 启动就完了。大错特错。Flask 应用必须为生产环境做三处关键改造移除debugTrue和host0.0.0.0开发时app.run(debugTrue, host0.0.0.0)方便调试但生产中debugTrue会开启 Werkzeug 的交互式调试器暴露代码执行入口是严重安全漏洞。必须删除或设为False。host0.0.0.0在 uWSGI 下无效因为 uWSGI 控制监听地址。显式定义if __name__ __main__:块确保应用模块能被 uWSGI 正确导入。标准结构如下# app.py from flask import Flask import os app Flask(__name__) app.route(/) def hello(): return Hello from Flask on uWSGI! # 关键此块仅在直接运行此文件时执行uWSGI 不会执行它 if __name__ __main__: # 仅用于本地开发测试 app.run(host0.0.0.0, port5000, debugFalse)uWSGI 启动时会执行import app然后调用app对象即 Flask 实例因此app必须是模块顶层的可调用对象。数据库连接池化如果应用使用 SQLAlchemy必须配置连接池避免每个请求新建连接。在app.py中from flask_sqlalchemy import SQLAlchemy from sqlalchemy import create_engine from sqlalchemy.pool import QueuePool app.config[SQLALCHEMY_DATABASE_URI] mysql://user:passlocalhost/db app.config[SQLALCHEMY_POOL_SIZE] 10 app.config[SQLALCHEMY_MAX_OVERFLOW] 20 app.config[SQLALCHEMY_POOL_TIMEOUT] 30 app.config[SQLALCHEMY_POOL_RECYCLE] 3600 db SQLAlchemy(app)POOL_RECYCLE3600是关键它强制连接每小时重连一次防止 MySQL 的wait_timeout默认 28800 秒导致连接失效。Ubuntu 14.04 的 MySQL 5.5 版本对此尤其敏感。3.3 uWSGI 配置文件详解.ini文件里的 12 个生死参数uWSGI 启动方式有两种命令行参数或配置文件。生产环境必须用配置文件如myapp.ini便于管理、复用和版本控制。以下是针对 Ubuntu 14.04 的最小可行配置逐行解析# myapp.ini [uwsgi] # 1. 应用路径 chdir /var/www/myapp module app:app # 2. Python 解释器路径显式指定避免混淆 home /usr # 3. 进程管理 master true processes 4 # 4. 通信方式关键用 Unix socket比 TCP 更快更安全 socket /var/run/uwsgi/myapp.sock chmod-socket 664 chown-socket www-data:www-data # 5. 安全与稳定性 vacuum true die-on-term true harakiri 30 max-requests 1000 # 6. 日志 logto /var/log/uwsgi/myapp.log log-maxsize 10000000 log-backupname /var/log/uwsgi/myapp.log.oldchdir和modulechdir指定工作目录module app:app表示从app.py文件中导入名为app的 Flask 实例。路径必须绝对且 uWSGI 进程要有读取权限。home显式指定 Python 安装路径。Ubuntu 14.04 的 Python 在/usr设为/usr可避免 uWSGI 找不到libpython2.7.so。若用虚拟环境此处应为虚拟环境路径如/var/www/myapp/venv。processes 4worker 进程数。经验公式2 × CPU 核心数 1。一台 2 核服务器设为 5。但 Ubuntu 14.04 内存紧张4 是平衡点。过多进程会触发 OOM Killer。socket相关这是 Nginx 与 uWSGI 通信的桥梁。/var/run/uwsgi/是标准 Unix socket 存放目录。chmod-socket 664设为组可读写chown-socket www-data:www-data确保 Nginx运行用户为www-data能访问。若权限不对Nginx 日志会报connect() to unix:/var/run/uwsgi/myapp.sock failed (13: Permission denied)。vacuum trueuWSGI 退出时自动删除 socket 文件。否则下次启动会因“Address already in use”失败。harakiri 30Worker 处理单个请求超过 30 秒强制杀死并重启。防止死循环或慢查询拖垮整个服务。max-requests 1000每个 worker 处理 1000 个请求后自动重启。这是对抗 Python 内存碎片化的有效手段Ubuntu 14.04 的老旧 glibc 对内存管理不如新版。日志参数log-maxsize限制单个日志文件大小log-backupname指定轮转后的文件名。避免日志撑爆磁盘——这是 Ubuntu 14.04 服务器最常见的宕机原因。注意/var/run/uwsgi/目录需手动创建并授权sudo mkdir -p /var/run/uwsgi sudo chown www-data:www-data /var/run/uwsgi sudo chmod 755 /var/run/uwsgi4. 实操过程与核心环节实现从零开始搭建可验证的服务4.1 创建项目结构与基础 Flask 应用我们以一个极简的图书 API 为例全程在 Ubuntu 14.04 终端操作# 创建项目目录 sudo mkdir -p /var/www/bookapi sudo chown $USER:$USER /var/www/bookapi cd /var/www/bookapi # 初始化虚拟环境强烈推荐隔离依赖 virtualenv venv source venv/bin/activate # 安装 Flask pip install Flask0.12.5 # Ubuntu 14.04 兼容的最新 Flask 0.x 版本 # 创建应用文件 nano app.pyapp.py内容如下from flask import Flask, jsonify, request import os app Flask(__name__) # 模拟数据库 BOOKS [ {id: 1, title: Flask Web Development, author: Miguel Grinberg}, {id: 2, title: Nginx Essentials, author: Vladimir Kulev} ] app.route(/api/books, methods[GET]) def get_books(): return jsonify(BOOKS) app.route(/api/books, methods[POST]) def add_book(): data request.get_json() if not data or title not in data or author not in data: return jsonify({error: Missing title or author}), 400 new_id max([b[id] for b in BOOKS], default0) 1 new_book {id: new_id, title: data[title], author: data[author]} BOOKS.append(new_book) return jsonify(new_book), 201 # 关键生产环境禁用 debug if __name__ __main__: app.run(debugFalse)测试本地运行python app.py # 访问 http://localhost:5000/api/books应返回 JSON 数据4.2 安装与配置 uWSGI# 在虚拟环境中安装 uWSGI pip install uwsgi2.0.18 # Ubuntu 14.04 兼容的稳定版本 # 创建 uWSGI 配置文件 nano myapp.ini # 粘贴前面详解的配置注意修改 chdir 和 modulemyapp.ini关键修改[uwsgi] chdir /var/www/bookapi module app:app home /var/www/bookapi/venv # 其他参数同上启动 uWSGI 测试# 启动前台运行方便看日志 uwsgi --ini myapp.ini # 应看到类似输出 # *** Starting uWSGI 2.0.18 (64bit) on [Mon Jan 1 12:00:00 2024] *** # *** Python version: 2.7.6 (default, Nov 23 2017, 15:49:48) *** # *** WSGI app 0 (mountpoint) ready in 0 seconds on interpreter 0x1a2b3c4d5e6f7890 *** # *** uWSGI is running in multiple interpreter mode *** # *** spawned uWSGI master process (pid: 1234) *** # *** spawned uWSGI worker 1 (pid: 1235, cores: 1) *** # *** spawned uWSGI worker 2 (pid: 1236, cores: 1) ***此时/var/run/uwsgi/bookapi.sock文件应已生成且权限为srw-rw-r--属主www-data。4.3 配置 Nginx 作为反向代理# 安装 Nginx sudo apt-get install nginx # 停止默认站点 sudo rm /etc/nginx/sites-enabled/default # 创建我们的站点配置 sudo nano /etc/nginx/sites-available/bookapi/etc/nginx/sites-available/bookapi内容server { listen 80; server_name localhost; # 生产中替换为真实域名 # 静态文件如有 location /static { alias /var/www/bookapi/static/; expires 1h; add_header Cache-Control public, immutable; } # API 请求全部代理到 uWSGI location / { include uwsgi_params; # Nginx 自带的 uWSGI 参数文件 uwsgi_pass unix:/var/run/uwsgi/bookapi.sock; uwsgi_read_timeout 30; uwsgi_send_timeout 30; # 传递关键头信息 uwsgi_param SCRIPT_NAME ; uwsgi_param PATH_INFO $uri; uwsgi_param UWSGI_CHDIR /var/www/bookapi; uwsgi_param UWSGI_MODULE app:app; } # 错误页面 error_page 500 502 503 504 /50x.html; location /50x.html { root /usr/share/nginx/html; } }启用站点sudo ln -s /etc/nginx/sites-available/bookapi /etc/nginx/sites-enabled/ sudo nginx -t # 测试配置语法 # 应输出nginx: the configuration file /etc/nginx/nginx.conf syntax is ok # nginx: configuration file /etc/nginx/nginx.conf test is successful sudo service nginx restart4.4 启动服务并验证端到端流程现在uWSGI 和 Nginx 都已配置但 uWSGI 还在前台运行。我们需要让它以后台服务方式运行# 创建 uWSGI 启动脚本简化版 sudo nano /etc/init.d/uwsgi-bookapi内容#!/bin/bash # /etc/init.d/uwsgi-bookapi case $1 in start) echo Starting uWSGI for bookapi /var/www/bookapi/venv/bin/uwsgi --ini /var/www/bookapi/myapp.ini ;; stop) echo Stopping uWSGI for bookapi kill cat /var/run/uwsgi/bookapi.pid 2/dev/null 2/dev/null || true ;; restart) $0 stop sleep 2 $0 start ;; *) echo Usage: $0 {start|stop|restart} exit 1 ;; esac exit 0赋予执行权限并注册为服务sudo chmod x /etc/init.d/uwsgi-bookapi sudo update-rc.d uwsgi-bookapi defaults启动服务sudo service uwsgi-bookapi start sudo service nginx restart最终验证# 用 curl 测试 curl http://localhost/api/books # 应返回 JSON 数组 # 查看 uWSGI 日志 sudo tail -f /var/log/uwsgi/bookapi.log # 查看 Nginx 错误日志定位 502 的黄金位置 sudo tail -f /var/log/nginx/error.log如果一切顺利你将看到完整的请求链路curl - Nginx - uWSGI socket - Flask app - uWSGI - Nginx - curl。整个过程不经过任何 Python 开发服务器完全符合生产标准。5. 常见问题与排查技巧实录那些让你抓狂的 502、504 和 Segmentation Fault5.1 “502 Bad Gateway” —— Nginx 与 uWSGI 的握手失败这是最常见、最让人崩溃的错误。Nginx 日志中会明确记录2024/01/01 12:00:00 [error] 1234#0: *1 connect() to unix:/var/run/uwsgi/bookapi.sock failed (111: Connection refused) while connecting to upstream或2024/01/01 12:00:00 [error] 1234#0: *1 connect() to unix:/var/run/uwsgi/bookapi.sock failed (13: Permission denied) while connecting to upstream排查四步法确认 uWSGI 进程是否在运行ps aux | grep uwsgi # 应看到 master 进程和多个 worker 进程 # 若无检查 /var/log/uwsgi/bookapi.log 是否有 ImportError确认 socket 文件是否存在且权限正确ls -l /var/run/uwsgi/bookapi.sock # 正确输出srw-rw-r-- 1 www-data www-data 0 Jan 1 12:00 /var/run/uwsgi/bookapi.sock # 若属主不是 www-data执行sudo chown www-data:www-data /var/run/uwsgi/bookapi.sock确认 Nginx 配置中的uwsgi_pass路径与 uWSGI 的socket路径完全一致包括大小写和斜杠。检查 uWSGI 日志的首行如果 uWSGI 启动失败日志第一行通常是ImportError: No module named app说明chdir或module配置错误。此时进入/var/www/bookapi目录手动执行python -c import app看是否报错。实操心得我有个习惯在myapp.ini中加一行daemonize /var/log/uwsgi/bookapi-daemon.log让 uWSGI 启动时把 daemon 日志单独输出比混在主日志里更容易定位启动失败原因。5.2 “504 Gateway Timeout” —— 请求处理超时Nginx 日志2024/01/01 12:00:30 [error] 1234#0: *1 upstream timed out (110: Connection timed out) while reading response header from upstream这表示 Nginx 等待 uWSGI 响应超过了uwsgi_read_timeout默认 60 秒。原因有二uWSGI worker 真的卡死了检查harakiri是否生效。在myapp.ini中增加harakiri-verbose trueuWSGI 会在日志中打印被杀死的 worker ID 和原因。Nginx timeout 设置过短在 Nginx 配置中uwsgi_read_timeout必须大于 uWSGI 的harakiri值。例如uWSGI 设harakiri 30Nginx 就应设uwsgi_read_timeout 35。5.3 uWSGI 编译失败gcc: internal compiler errorUbuntu 14.04 的 gcc 4.8.2 在编译大型 C 扩展时偶发崩溃。解决方案升级 gcc谨慎sudo apt-get install software-properties-common sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-4.9 g-4.9 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 50更稳妥的方案用--no-cache-dir和--force-reinstallpip install --no-cache-dir --force-reinstall uwsgi2.0.185.4 Flask 应用中request.json为 None这是新手高频坑。当你用curl -H Content-Type: application/json -d {key:value} http://localhost/api/books发送 POSTFlask 却收到空数据。原因在于uWSGI 默认不传递原始请求体需要显式配置在myapp.ini中添加# 确保 uWSGI 传递原始 body buffer-size 8192 # 如果用 JSON还需设置 wsgi-disable-file-wrapper true并在 Flask 中用request.get_data()获取原始字节再手动json.loads()。5.5 内存泄漏与进程僵死Ubuntu 14.04 的老旧内核对进程回收不敏感。uWSGI worker 运行数小时后ps aux --sort-%mem | head可能显示某个 worker 占用内存飙升。此时max-requests就是救命稻草。我通常设为500比默认 1000 更激进并配合reload-on-rss 200worker RSS 内存超 200MB 时重启。常见问题速查表现象根本原因快速修复502 Bad Gateway, Nginx 日志报Connection refuseduWSGI 未启动或 socket 路径错误sudo service uwsgi-bookapi start检查myapp.ini的socket和 Nginx 的uwsgi_pass502 Bad Gateway, Nginx 日志报Permission deniedsocket 文件权限不足sudo chown www-data:www-data /var/run/uwsgi/*.sockImportError: No module named appuWSGI 找不到 app.py 或模块名错误进入chdir目录执行python -c import app检查module app:appSegmentation fault (core dumped)uWSGI 与 Python 版本不兼容降级 uWSGI 到2.0.18确保home指向正确的 Python 路径POST 请求request.json为 NoneuWSGI 未正确传递请求体在myapp.ini中添加buffer-size 81926. 后续演进与生产加固从能跑到稳再到可信这套 Ubuntu 14.04 uWSGI Nginx 的组合是“能跑”的基线。要达到“稳”和“可信”还需三步加固日志集中化Ubuntu 14.04 的rsyslog仍可用。配置/etc/rsyslog.d/10-uwsgi.conf将 uWSGI 日志通过 UDP 发送到远程日志服务器避免本地磁盘写满。进程守护init.d脚本是基础但不够智能。可引入supervisordpip install supervisor它能自动重启崩溃进程、记录 stdout/stderr、提供 Web 管理界面。配置简单一行命令supervisord -c /etc/supervisor/conf.d/bookapi.conf即可接管。SSL 终止生产环境必须 HTTPS。Nginx 配置中添加listen 443 ssl; ssl_certificate /etc/ssl/certs/bookapi.crt; ssl_certificate_key /etc/ssl/private/bookapi.key; ssl_protocols TLSv1.2; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;使用 Lets Encrypt 的certbot需先升级 Ubuntu 14.04 的python-acme包可免费获取证书。最后分享一个小技巧在myapp.ini中加入stats 127.0.0.1:9191然后用uwsgi --stats 127.0.0.1:9191可实时查看 uWSGI 的 worker 状态、请求数、响应时间分布。这是诊断性能瓶颈的“透视眼”比看日志高效十倍。我在一个政务系统上线前就是靠这个发现了某个 API 接口平均响应时间高达 8 秒最终定位到是 MySQL 查询未加索引。这套组合拳打下来Ubuntu 14.04 不再是负担而是一台值得信赖的生产基石。