最稳、最轻量的方案是mod_proxy_uwsgi,需uWSGI监听uwsgi协议、Apache启用proxy和proxy_uwsgi模块且配置严格匹配,禁用HTTP/SCGI混用,Unix socket需权限一致。

直接用 mod_proxy_uwsgi 是当前 Apache + Python(Django/Flask)生产部署中最稳、最轻量的方案,比 mod_wsgi 更解耦,比 mod_proxy_http 更高效 —— 但前提是 uWSGI 必须监听 uwsgi 协议,且 Apache 配置里不能混用 http:// 或 scgi://。
确认 mod_proxy_uwsgi 已启用且版本兼容
Apache 2.4.25+ 自带 mod_proxy_uwsgi,旧版需手动编译(如 2.0.2 分支的 mod_proxy_uwsgi.c)。Debian/Ubuntu 上运行:a2enmod proxy proxy_uwsgi;RHEL/CentOS 则检查 /etc/httpd/conf.modules.d/00-proxy.conf 是否有这行:LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so。
常见错误现象:Invalid command 'ProxyPass', perhaps misspelled 或日志报 proxy_uwsgi_module not found。
- 必须同时启用
proxy_module(核心代理模块),否则mod_proxy_uwsgi不会加载 - 不要尝试用
apxs -c编译第三方源码 —— 现代发行版已内置,手动编译易导致 ABI 不兼容,引发 segfault - 验证是否生效:
httpd -M | grep uwsgi或apache2ctl -M | grep uwsgi,应输出proxy_uwsgi_module (shared)
uWSGI 必须用 uwsgi 协议监听,且地址格式严格
mod_proxy_uwsgi 只认 uwsgi:// 前缀,后端必须是 uWSGI 实例,并启用原生 uwsgi 协议(不是 HTTP,也不是 SCGI)。配置示例如下:
[uwsgi] socket = 127.0.0.1:3031 # 不要写 http-socket 或 scgi-socket chdir = /var/www/myapp module = myapp.wsgi:application processes = 4 threads = 2 vacuum = true
关键点:
-
socket必须是IP:PORT形式(如127.0.0.1:3031)或Unix socket路径(如/run/uwsgi/myapp.sock),但 Apache 配置中对应要写成uwsgi://127.0.0.1:3031/或uwsgi:///run/uwsgi/myapp.sock - 若用 Unix socket,Apache 进程(通常是
www-data或apache用户)必须对 socket 文件有读写权限,且 SELinux/AppArmor 未拦截(CentOS 常见问题) - 禁止在 uWSGI 配置里加
--http :8000—— 这会让它监听 HTTP,和mod_proxy_uwsgi完全不搭界
ProxyPass 指令格式与 SCRIPT_NAME 处理
Apache 配置段中,ProxyPass 的 URL 必须以 uwsgi:// 开头,末尾斜杠决定 SCRIPT_NAME 值:
ProxyPass / uwsgi://127.0.0.1:3031/ ProxyPass /api uwsgi://127.0.0.1:3031/api
注意:
- 第一行末尾有
/→ uWSGI 收到的SCRIPT_NAME为空字符串,PATH_INFO为原始路径(如/login) - 第二行末尾无
/→ uWSGI 收到的SCRIPT_NAME是/api,PATH_INFO变成/login(当请求是/api/login时) - 若应用实际挂载在子路径(如
https://example.com/myapp/),必须配ProxyPass /myapp/ uwsgi://...并确保 uWSGI 应用内路由也适配该前缀 - 不要加
ProxyPassReverse—— 它对uwsgi://无效,Apache 会忽略;重定向由 uWSGI 或应用自身控制
调试连接失败的三个必查点
现象:页面空白、503、或 Apache error log 里反复出现 Connection refused、Timeout when reading response headers。
- 先 telnet 或 nc 测试 uWSGI 是否真在监听:
nc -zv 127.0.0.1 3031。连不上说明 uWSGI 没启、端口错、或 bind 到了127.0.0.1但 Apache 尝试走 IPv6(可改用localhost或显式指定::1) - 检查 uWSGI 日志(
daemonize或logto指定的文件),确认有没有bind(): Address already in use或unable to load app 0 (mountpoint='') - Apache 的
ErrorLog里若出现uwsgi: response header overflow,大概率是 uWSGI 返回了超长响应头(比如重复 set-cookie),需调大uWSGIMaxVars(默认 128):uWSGIMaxVars 256
最易被忽略的是 uWSGI 的 chmod-socket 权限(Unix socket 场景)和 Apache 进程用户身份不一致 —— 表现为连接瞬间断开,日志却无明确报错。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











