49
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[apache] ProxyPreserveHostをOnにしてハマる

Last updated at Posted at 2014-10-31

apacheによるリバースプロキシを多段構成にしていて、バックエンドでもクライアントがリクエストしたホスト名を取りたい!なんてことがありました。
ProxyPreserveHostを設定すれば解決するじゃん!という答えに行き着いたのですが、ハマることがあったのでメモしておきます。

参考

やりたいこと

以下の構成をとったとき、バックエンドでクライアントがリクエストしたホスト名を取りたい。しかし多段プロキシの影響によりlocalhostが取れてしまう。

cliant -> proxy1(apache) -> proxy2(apache) -> backend

単純に対応すると

上記proxy1, proxy2のコンフィグに以下を追記すればclientがリクエストしたホスト名がそのまま渡ってきます。が、他の設定に影響を与えるため注意が必要です。

apache.conf
  ProxyPreserveHost On

ProxyPassReverseにハマる

リバースプロキシを使う際、リダイレクトの対応としてProxyPassReverseを設定することがよくあります。
しかし、以下のような書き方をしているとProxyPassReverseが効かなくなります。

apache.conf
## リバースプロキシの設定
  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-Forwaeded-HostかHostを見てる?)
バックエンドがlocalhost:3080にリダイレクトさせるはずが、myhost:3080で返してくるため、ProxyPassReverseに引っかからなくなっています。
期待通りにリダイレクトのホスト名を書き換えようと思うと以下の対応が必要です

解決案1:ProxyPassReverseを書き換える

クライアントがリクエストするホスト名をベタっと書いてしまう

apache.conf
  ProxyPass /ja http://localhost:3080/ja
  ProxyPassReverse /ja http://myhost.com:3080/ja

解決案2:バックエンドでServerNameを使う

バックエンド自身にlocalhost、もしくはクライアントがリクエストするホスト名を名乗らせることでも解決します。クライアントがリクエストするホスト名を名乗らせた場合、ProxyPassReverseの設定自体が不要になります

apache.conf
  ServerName myhost.com:80 または ServerName localhost:3080 とか
  UseCanonicalName on #これをセットで記述しないと有効になりません

SSLProxyにハマる

SSLProxyを利用している場合、プロキシ先の証明書とリクエストのホスト名が不一致となりプロキシに失敗してしまいます。
例えばこんな設定を書いていたとすると、

apache.conf
  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

(暫定)解決案 とりあえず証明書の確認をスキップ

プロキシ先のサーバが信頼できる必要がありますが、証明書の確認をスキップすることで回避できます。そうでない場合は真面目に確認が必要ですが、今回はそこまで調べていません・・・。

apache.conf
  SSLProxyEngine on
  SSLProxyCheckPeerCN off
  SSLProxyCheckPeerName off
  ProxyPass /other https://myhost2.com/other
49
55
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?