如何在.htaccess中检测代理?及Moodle重写规则异常排查
嘿,我来帮你拆解这两个问题,都是.htaccess里常见的小坑,咱一步步来:
一、不同Moodle部署场景的RewriteRule问题分析
1. 子域名场景(moodle.mysite.com)为啥正常?
当Moodle部署在子域名时,你用的RewriteRule ^.*$ /****/******.php [NC,L](注意你原来的规则里[NC, L]多了个空格,标准写法是[NC,L])能正常跑,是因为这个规则只是做内部重写,没有触发反向代理逻辑。请求的主机头明确是moodle.mysite.com,Apache直接把请求转到目标PHP文件,自然没毛病。
2. 子目录场景(http(s)://mysite.com/moodle)的错误原因
你碰到的DNS lookup failure for: nodomainamen:8080http错误,说白了就是Apache的反向代理模块被误触发后,拿到了一个拼错的目标地址,导致解析域名失败。
而你换的RewriteRule ^.*$ /****/******.php?requete=%{REQUEST_URI}? [P]能正常工作,核心原因有两个:
[P]flag明确告诉Apache要做反向代理,而且规则里的目标路径是有效的- 你通过
?requete=%{REQUEST_URI}?把原始请求路径传了过去,末尾的?还能清除原有的查询字符串,避免参数乱掉 - 这个规则完美适配了子目录的场景,目标PHP文件可以通过
$_GET['requete']拿到原始请求路径,从而正确处理业务逻辑
子目录场景的规则优化建议
如果你不想传递查询参数,只想做内部重写(不用反向代理),可以试试这个规则:
# 先匹配mysite.com下的/moodle子目录请求 RewriteCond %{HTTP_HOST} ^mysite\.com$ [NC] RewriteCond %{REQUEST_URI} ^/moodle/ [NC] # 去掉/moodle前缀后,把剩余路径传给目标PHP RewriteRule ^moodle/(.*)$ /****/******.php?requete=$1 [NC,L]
如果必须用反向代理(保留[P]),记得先确认Apache的mod_proxy和mod_proxy_http模块已经启用,而且目标路径是正确的绝对路径或者完整URL(如果是代理到外部服务器的话)。
二、在.htaccess中检测代理的方法
要判断请求是否来自代理服务器,主要靠检查请求头里的代理专属字段,用RewriteCond就能实现:
1. 检查常见的代理请求头
# 只要满足任意一个代理头条件,就标记为代理请求 RewriteCond %{HTTP_X_FORWARDED_FOR} !^$ [OR] RewriteCond %{HTTP_X_FORWARDED_PROTO} !^$ [OR] RewriteCond %{HTTP_VIA} !^$ [OR] RewriteCond %{HTTP_FORWARDED} !^$ # 设置环境变量IS_PROXY为1,方便后续判断 RewriteRule ^ - [E=IS_PROXY:1]
简单解释下这些请求头:
HTTP_X_FORWARDED_FOR:代理服务器会加这个头,记录原始客户端的真实IPHTTP_X_FORWARDED_PROTO:记录用户发起请求时用的协议(http/https)HTTP_VIA:显示请求经过的代理服务器信息HTTP_FORWARDED:这是标准的代理请求头,包含客户端IP、代理地址等完整信息
2. 检查客户端IP是否在已知代理段
如果你有固定的代理IP范围,可以直接匹配:
# 匹配192.168.1.*或10.0.0.*段的IP RewriteCond %{REMOTE_ADDR} ^192\.168\.1\. [OR] RewriteCond %{REMOTE_ADDR} ^10\.0\.0\. RewriteRule ^ - [E=IS_PROXY:1]
之后不管是在.htaccess的后续规则里,还是在PHP代码中,都可以通过%{ENV:IS_PROXY}或者getenv('IS_PROXY')来判断是否是代理请求。
内容的提问来源于stack exchange,提问作者Dey

