•
Freeshell 上的 HTTP 服务器在使用 HTTP Proxy 时,请求的来源 IP 是代理服务器的内网 IP,而请求协议也都是 HTTP(HTTPS 证书和加解密已经在 HTTP Proxy 上处理了)。要知道客户端的真实 IP 和 HTTP/HTTPS 协议,可以使用 HTTP header 中的下列字段:
X-Forwarded-For
: 客户端 IP 地址,可能是 IPv4 或 IPv6 地址X-Real-IP
: 同X-Forwarded-For
X-Forwarded-Proto
: 客户端是通过 http 还是 https 访问的,值可能是 http 或 httpsX-Scheme
: 同X-Forwarded-Proto
其中 X-Forwarded-Proto
是今天(2015年2月26日)新加的 HTTP Header,因为 X-Forwarded-For
和 X-Forwarded-Proto
是 HTTP 代理服务器的事实标准。
要让 WordPress、Discuz 等 PHP 程序能够正确识别用户的真实 IP 和 HTTP 请求协议,可以把上述 HTTP Header 作为服务器的环境变量传递给 PHP 程序。
Nginx
Freeshell 上如果安装的是 Nginx + FastCGI,可以在 nginx 配置文件中的 server 块以外添加如下代码:
map $http_x_forwarded_proto $proxy_https {
default off;
https on;
}
然后在 location 块内的 include fastcgi_params;
一行下面添加
fastcgi_param remote_addr $http_x_forwarded_for;
fastcgi_param https $proxy_https;
在 PHP 程序中,$_SERVER['REMOTE_ADDR']
就会变成客户端的真实 IP;而客户端是否通过 https 来访问,可以通过 $_SERVER['HTTPS']
是否为 on 来判断。
Apache
Freeshell 上如果安装的是 Apache 2,建议安装 mod_rpaf 模块,该模块可以根据 X-Forwarded-For
和 X-Forwarded-Proto
正确设置 PHP 环境变量。
如果不想安装模块,可以如下解决:
- 客户端 IP:由于 Apache 不允许修改
REMOTE_ADDR
,需要修改 PHP 代码,首先尝试$_SERVER['X_FORWARDED_FOR']
变量,如果存在就把它作为客户端 IP;如果不存在,再使用$_SERVER['REMOTE_ADDR']
。Discuz 已经这样做了,但 WordPress 没有这样做,需要自己改或安装相关插件。 -
客户端 HTTP/HTTPS:在 Apache 配置文件中添加如下代码:
SetEnvIf X-Forwarded-Proto https HTTPS=On
PHP 程序中可以通过
$_SERVER['HTTPS']
是否为 on 来判断。
感谢 崔天一 和 郑子涵 提出问题。