打开[apache] 的ProxyPreserveHost并遇到问题
我在使用Apache进行多级反向代理配置,希望能够在后端获取到客户端请求的主机名!我最后得出的答案是设置ProxyPreserveHost就可以解决问题,但是由于遇到了一些困难,所以我把这些内容记录在这里。
可以参考
-
- リバースプロキシの多段構成によるRailsアプリへの影響 Ruby – Rack::Request#hostがX-Forwarded-Hostの最後のプロキシホストを返す理由 – Qiita
ProxyPreserveHostの公式ドキュメント
想做的事情
当使用以下配置时,希望在后端能够获取到客户端请求的主机名。然而,由于多级代理的影响,可能会得到localhost。
cliant -> proxy1(apache) -> proxy2(apache) -> backend
若只是简单地做出回应
如果在上述proxy1和proxy2的配置中添加以下内容,那么客户端请求的主机名将被原封不动地传递过来。但由于可能会影响其他设置,需要注意。
ProxyPreserveHost On
陷入ProxyPassReverse的困境中。
在使用反向代理时,经常会设置ProxyPassReverse作为重定向的解决方案。然而,如果采用以下方式,ProxyPassReverse将失效。
## リバースプロキシの設定
ProxyPass /ja http://localhost:3080/ja
ProxyPassReverse /ja http://localhost:3080/ja
## リダイレクトでこんな設定があるとして
redirect /ja/hoge /ja
期待如此,应该会这样。
$ curl -I http://myhost.com/ja/hoge
HTTP/1.0 302 Moved Temporarily
...
Location: http://myhost.com/ja
然而,实际上会返回带有非预期的端口号。
$ curl -I http://myhost.com/ja/hoge
HTTP/1.0 302 Moved Temporarily
...
Location: http://myhost.com:3080/ja
由于请求头的值被ProxyPreserveHost改变,似乎会发生以下情况(是查看X-Forwarded-Host还是Host?)。
预期后端应该将重定向发送到localhost:3080,但实际上返回的是myhost:3080,因此不再被ProxyPassReverse捕获。
要按预期修改重定向的主机名,需要执行以下操作:
解决方案1:修改ProxyPassReverse
直接写下客户端请求的主机名。
写下客户端请求的主机名。
ProxyPass /ja http://localhost:3080/ja
ProxyPassReverse /ja http://myhost.com:3080/ja
解决方案2:在后端使用ServerName
通过让后端本身代表本地主机或客户端请求的主机名来解决问题。如果客户端请求的主机名被代表,那么就不需要设置ProxyPassReverse的配置。
ServerName myhost.com:80 または ServerName localhost:3080 とか
UseCanonicalName on #これをセットで記述しないと有効になりません
迷上了SSL代理 SSL
如果使用SSLProxy,代理目标的证书和请求的主机名不匹配,代理将失败。
例如,假设有这样的设置:
SSLProxyEngine on
ProxyPass /other https://myhost2.com/other
会出现这样的错误。
[ssl:info] [pid xxxx] [remote x.x.x.x:443] AH02005: SSL Proxy: Peer certificate CN mismatch: Certificate CN: myhost2.com Requested hostname: myhost.com
目前的解决方案是先跳过证明文件的确认。
代理服务器必须是可信赖的,可以通过跳过证书验证来避免验证。否则,必须认真进行验证,但这次我们没有深入研究…
SSLProxyEngine on
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
ProxyPass /other https://myhost2.com/other