这种小概率技术问题某种意义上也算是天·朝专利了:)
本文集中介绍阿里云(aliyun.com)中,使用反向代理规避备案风险。
还有如何在 SAE(Sina App Engine http://sae.sina.com.cn/ )中使用自有反向代理。
您需要一个境外服务器(不需要备案的服务器),作为代理服务器:)
访问流程
本文使用apache http作为http和proxy服务器。
- 客户端向代理服务器请求的 Host 为: test.com
- 代理服务器向http服务器请求含有 X-Forwarded-Host: test.com 。
- 当 ProxyPreserveHost On 时,客户端提供的 Host 会被传递到http服务器:test.com
- 当 ProxyPreserveHost Off 时,ProxyPass 指定的 Host 会被传递到http服务器:192.168.1.333(SAE:xxx.sinaapp.com)
- http服务器根据代理服务器指定的 Host 来判定应该使用哪个虚拟主机。
基本配置
httpd:
<VirtualHost *:80>
ServerName zoeey.org
ServerAlias *.zoeey.org
DocumentRoot /sites/zoeey
<Directory "/sites/zoeey">
FileETag MTime Size
Options FollowSymLinks
AllowOverride all
SetEnvIf X-Forwarded-For "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" is_pass
SetEnvIfNoCase Host "\.zoeey\.org$" is_pass
Order Deny,Allow
Deny from all
Allow from env=is_pass
</Directory>
</VirtualHost>
阿里云(aliyun)用户注意这里的allow设置。允许主域名和反向代理访问。
阿里云不允许空主机头,也就是需要将第一个vhost设置为deny。
上述的设置方式是允许以代理的方式访问空主机头,可用于用户自定义域名绑定。
PHP中获取用户访问时请求的Host:
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$domain = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else {
$domain = getenv('HTTP_HOST');
}
proxy:
<VirtualHost *:80>
ProxyPass / http://192.168.1.333/
# SAE # ProxyPass / http://xxx.sinaapp.com/
# ProxyPreserveHost On
</VirtualHost>
无论是SAE还是阿里云现在均不能直接绑定未备案域名,且不可以代理形式传递 Host 。
所以proxy配置中 ProxyPreserveHost 应为 Off ,或删除掉该行。
上述配置可以实现:
1、用户免备案绑定独立域名,并绑定在httpd首个vhost指定的目录上。
2、使用自己的反向代理服务器为尚未备案的SAE应用绑定自己的域名。
使用 X-Forwarded-Host 的 VirtualHost 绑定
当代理服务器的ProxyPreserveHost关闭时,Host 的传递被切换。
客户端提供的 Host 名称仅由 X-Forwarded-Host 持有。
此时我们不能使用传统的根据 Host 配置 VirtualHost 目录绑定。
下面介绍 httpd 如何使用 X-Forwarded-Host 绑定。
找到获取绑定所需 Host 名称的方法: ap_update_vhost_from_headers。
并先行判定 X-Forwarded-Host。
具体修改位置与方法如下。
httpd-2.2.17/server/vhost.c
AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
{
r->hostname = apr_table_get(r->headers_in, "X-Forwarded-Host");
/* must set this for HTTP/1.1 support */
if (r->hostname || (r->hostname = apr_table_get(r->headers_in, "Host"))) {
fix_hostname(r);
if (r->status != HTTP_OK)
return;
}
/* check if we tucked away a name_chain */
if (r->connection->vhost_lookup_data) {
if (r->hostname)
check_hostalias(r);
else
check_serverpath(r);
}
}
我们增加了 X-Forwarded-Host 获取,其优先于 Host 。
实际使用可参考 use_canonical_name_xhost-trunk.patch 中的 ap_get_xhost_from_headers 函数。
重新编译安装httpd即可。
参考资料
mod_proxy
ProxyPreserveHost
SetEnvIfNoCase
mod_mbox/httpd-dev/201205.mbox/%3C4FA30D5A.3040406@pearsoncmg.com%3E
use_canonical_name_xhost-trunk.patch
SEO
sae免备案
aliyun免备案
代理无法绑定域名
反向代理无法绑定域名
不传递 Host 的 vhost 绑定
不传递 Host 的 VirtualHost 绑定
ProxyPreserveHost Off,VirtualHost 绑定
X-Forwarded-Host VirtualHost 绑定
由 moxie 撰写 http://blog.zoeey.org/2012/06/15/client-proxy-httpd/