mod_proxy_scgi是Apache用于代理HTTP请求到SCGI后端的模块,适用于低延迟高吞吐的内部通信场景,但因SCGI已被主流框架弃用,仅推荐用于遗留系统维护。

mod_proxy_scgi 是什么,它适合什么场景
mod_proxy_scgi 是 Apache 的一个代理模块,用于将 HTTP 请求转发给支持 SCGI 协议的后端应用(比如 uWSGI、gunicorn 配置为 SCGI 模式、或自研 SCGI 服务)。它不是通用 HTTP 代理,也不等同于 mod_proxy_http;SCGI 是一种轻量二进制协议,比 FastCGI 更简单,比纯 HTTP 少一层解析开销,适合低延迟、高吞吐的内部通信。
但要注意:现代主流 Python 应用(如 Django/Flask)默认推荐用 uwsgi 协议或 HTTP,**SCGI 已基本被弃用**。uWSGI 自 2.0.18 起默认禁用 SCGI,gunicorn 从 20.1.0 开始完全移除 SCGI 支持。所以除非你维护遗留系统,否则不建议新项目选 SCGI。
常见错误现象:ProxyError: DNS lookup failure for: / 或 Connection refused,往往是因为后端根本没监听 SCGI,或 Apache 没启用模块。
启用 mod_proxy_scgi 并配置基础代理规则
Apache 默认不加载 mod_proxy_scgi,必须显式启用:
- 在 Debian/Ubuntu 上运行:
a2enmod proxy_scgi(同时需确保 proxy 已启用)
- 在 CentOS/RHEL 上编辑
/etc/httpd/conf.modules.d/00-proxy.conf,取消注释:LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
- 重启 Apache:
systemctl restart apache2 或 httpd
基础配置示例(放在 VirtualHost 内):
ProxyPass / scgi://127.0.0.1:4000/
ProxyPassReverse / scgi://127.0.0.1:4000/
注意:
-
scgi:// 协议前缀不能写成 http:// 或省略 —— 否则 Apache 会走 HTTP 代理逻辑,直接失败
- 后端地址必须是
IP:PORT 形式,不支持 Unix socket(SCGI 协议本身不定义 socket 路径格式,mod_proxy_scgi 不支持 scgi:///path/to/socket)
-
ProxyPassReverse 的 URL 必须和 ProxyPass 一致,否则响应头中的 Location 等不会重写
后端必须真正支持 SCGI 协议,且监听正确地址
Apache 的 mod_proxy_scgi 发送的是标准 SCGI 请求(含 CONTENT_LENGTH、SCGI 等环境变量,头部以 \x00 分隔),后端必须按 SCGI 规范解析,不能只接受 HTTP。
验证方式(命令行快速测试):
echo -ne "CONTENT_LENGTH\x000\x00SCRIPT_NAME\x00/\x00PATH_INFO\x00/\x00REQUEST_METHOD\x00GET\x00SERVER_PROTOCOL\x00HTTP/1.0\x00\x00" | nc 127.0.0.1 4000
如果返回 HTTP 响应(如 HTTP/1.0 200 OK),说明后端 SCGI 正常;如果连接立即关闭或返回乱码,说明协议不匹配。
常见踩坑点:
- uWSGI 启动时漏加
--scgi-socket 127.0.0.1:4000(不是 --http 或 --socket)
- uWSGI 配置中写了
protocol = scgi,但没配 scgi-socket,实际仍走默认 uwsgi 协议
- 防火墙或 SELinux 阻止了 4000 端口(尤其在 CentOS 上,
sestatus 和 setsebool -P httpd_can_network_connect 1 可能需要)
性能与安全限制:SCGI 没有内置超时/重试/健康检查
mod_proxy_scgi 的行为非常“原始”:它不解析 SCGI 响应体,不校验状态,不重试失败连接,也不提供连接池管理。所有超时都依赖底层 TCP 设置。
关键参数只有三个(必须手动设,否则容易卡死):
-
ProxyTimeout 30:设置整个 SCGI 请求的最大等待时间(单位秒),默认是 60,但很多后端超时更短,建议设为后端 read-timeout 的 1.5 倍
-
ProxyBadHeader Ignore:SCGI 响应头若含非法字符(如换行),Apache 默认拒绝,设为 Ignore 可绕过(但治标不治本)
-
ProxySet keepalive=On retry=5:启用长连接并设置故障后重试间隔(单位秒),对 SCGI 有效,但不保证请求重发
没有 ProxyStatus 或 balancer-manager 支持,无法做健康检查。如果后端挂了,Apache 会持续尝试连接直到超时,期间所有请求阻塞。
SCGI 本身不加密、无认证,**绝不能暴露到公网**。务必配合 Require ip 127.0.0.1 或防火墙限制后端端口访问范围。
实际部署中,SCGI 的“高性能”优势在千级 QPS 以上才略有体现,而维护成本远高于直接用 mod_proxy_http + 后端 HTTP 模式。真要压榨性能,不如用 mod_proxy_uwsgi 或直接上 Caddy/Nginx。
a2enmod proxy_scgi(同时需确保 proxy 已启用)/etc/httpd/conf.modules.d/00-proxy.conf,取消注释:LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
systemctl restart apache2 或 httpd
scgi:// 协议前缀不能写成 http:// 或省略 —— 否则 Apache 会走 HTTP 代理逻辑,直接失败IP:PORT 形式,不支持 Unix socket(SCGI 协议本身不定义 socket 路径格式,mod_proxy_scgi 不支持 scgi:///path/to/socket)ProxyPassReverse 的 URL 必须和 ProxyPass 一致,否则响应头中的 Location 等不会重写mod_proxy_scgi 发送的是标准 SCGI 请求(含 CONTENT_LENGTH、SCGI 等环境变量,头部以 \x00 分隔),后端必须按 SCGI 规范解析,不能只接受 HTTP。
验证方式(命令行快速测试):
echo -ne "CONTENT_LENGTH\x000\x00SCRIPT_NAME\x00/\x00PATH_INFO\x00/\x00REQUEST_METHOD\x00GET\x00SERVER_PROTOCOL\x00HTTP/1.0\x00\x00" | nc 127.0.0.1 4000如果返回 HTTP 响应(如
HTTP/1.0 200 OK),说明后端 SCGI 正常;如果连接立即关闭或返回乱码,说明协议不匹配。
常见踩坑点:
- uWSGI 启动时漏加
--scgi-socket 127.0.0.1:4000(不是--http或--socket) - uWSGI 配置中写了
protocol = scgi,但没配scgi-socket,实际仍走默认 uwsgi 协议 - 防火墙或 SELinux 阻止了 4000 端口(尤其在 CentOS 上,
sestatus和setsebool -P httpd_can_network_connect 1可能需要)
性能与安全限制:SCGI 没有内置超时/重试/健康检查
mod_proxy_scgi 的行为非常“原始”:它不解析 SCGI 响应体,不校验状态,不重试失败连接,也不提供连接池管理。所有超时都依赖底层 TCP 设置。
关键参数只有三个(必须手动设,否则容易卡死):
-
ProxyTimeout 30:设置整个 SCGI 请求的最大等待时间(单位秒),默认是 60,但很多后端超时更短,建议设为后端 read-timeout 的 1.5 倍
-
ProxyBadHeader Ignore:SCGI 响应头若含非法字符(如换行),Apache 默认拒绝,设为 Ignore 可绕过(但治标不治本)
-
ProxySet keepalive=On retry=5:启用长连接并设置故障后重试间隔(单位秒),对 SCGI 有效,但不保证请求重发
没有 ProxyStatus 或 balancer-manager 支持,无法做健康检查。如果后端挂了,Apache 会持续尝试连接直到超时,期间所有请求阻塞。
SCGI 本身不加密、无认证,**绝不能暴露到公网**。务必配合 Require ip 127.0.0.1 或防火墙限制后端端口访问范围。
实际部署中,SCGI 的“高性能”优势在千级 QPS 以上才略有体现,而维护成本远高于直接用 mod_proxy_http + 后端 HTTP 模式。真要压榨性能,不如用 mod_proxy_uwsgi 或直接上 Caddy/Nginx。
ProxyTimeout 30:设置整个 SCGI 请求的最大等待时间(单位秒),默认是 60,但很多后端超时更短,建议设为后端 read-timeout 的 1.5 倍ProxyBadHeader Ignore:SCGI 响应头若含非法字符(如换行),Apache 默认拒绝,设为 Ignore 可绕过(但治标不治本)ProxySet keepalive=On retry=5:启用长连接并设置故障后重试间隔(单位秒),对 SCGI 有效,但不保证请求重发


















