〔備忘録〕 Apache のリバースプロキシで内部 WordPress サーバを公開する
自前で用意した Web サーバで、WordPress のブログサイトを公開しようと思い、
次のような構成でサーバを準備しました。
(Internet) ------- (My Web Server @DMZ) ------ ( Wordpress Server @intra-net)
[HTTPS] [HTTP]
# 一応セキュリティのために、上記の "----" の間にはルーターが入っています。
上記の構成で、インターネットに Wordpress を公開するには、
My Web Server 上でReverse Proxyを構成すればいいと思ったのですが、
これが意外に簡単にできなかったので、備忘録としてメモします。
前提条件として、My Web Server は
WordPress は、
- PC: VirtualBox 5.1 上の仮想PC
- OS: Ubuntu 16.04 LTS
- Web: apache 2.4 (ubuntu package でインストール)
- PHP: php 7.0 (ubuntu pacakage でインストール)
- SQL: MySQL 5.7 (ubuntu package でインストール)
- WordPress: 日本語版の最新バージョンを https://jp.wordpress.org からダウンロードしてインストール
です。
補足)
やり方(結果)だけを見たい方は、この記事の最後の方だけを読んでください。
途中は失敗談をずらずらと書いています。 f(^^;;;
=================< 失敗談 >==================
失敗1)
単純に My Web Server で Reverse Proxy の設定をしました。
としたのですが、HTML 以外のコンテンツ(画像とか)が全く表示されません。
ProxyRequests Off
ProxyPass "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverse "/blog/" "http://internal-wordpress-server.invalid/"
実際に、HTML のソースコードを見ると、画像等のURLが内部の Wordpress サーバアドレスがそのまま書かれていました。 orz
失敗2)
とりあえず、 Google 先生に教えを乞いました。
その中で、
という方法が紹介されていたので、
以下のように設定を追加しました。
ProxyRequests Off
ProxyPass "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverse "/blog/" "http://internal-wordpress-server.invalid/"
ProxyReverseHost on
ProxyPassReverseCookieDomain internal-wordpress-server.invalid My-Web-Server.invalid
ProxyPassReverseCookiePath / /
結果は、最初と同じく、画像などが表示されません。
ただ、ヘッダーを見ると Cookie の中に書かれていた internal-wordpress-server.invalid というサーバ名が、外部公開用サーバ My-Web-Server.invalid に書き換えられていたので、この点ではちょっと進歩です。
ちなみに、ProxyReverseHostのドキュメントを見ると、
「バックエンドサーバ(この事例では Wordpress Server)が、元々の Host ヘッダを解釈する必要のあるときのような、 特別な設定が必要な場合にのみ有用です。」
と書かれていますので、
今回のケースでは必要ありませんでしたし、問題の解決にはつながりませんでした。
失敗3)
さらに、Google 先生に教えを乞うたところ、
以下のサイトを紹介していただきました。
- https://fixture.jp/blog/2012/02/how-to-work-wordpress-with-reverse-proxy/
- https://blog.supersonico.info/?p=1367
実際に、Wordpress 内の wp-config.php に以下を追記してみました。
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
すると、動作確認で使用していた firefox 君が
「ページの自動転送設定が正しくありません
このアドレスへのリクエストに対するサーバーの自動転送設定がループしています。
* Cookie を無効化したり拒否していることにより、この問題が発生している可能性もあります。」
と怒ってきました。
Google先生曰く、
もあるよ。
とのことで、まずは単純に、wp-config.php に
を追記したところ、上記サイトの言うようにリダイレクトループは無くなりました
$_SERVER[‘HTTPS’]=on
が、firefox 君曰く、
「internal-wordpress-server.invalid のサーバーへの接続を確立できませんでした。」
と文句を言ってきました。
当たり前ですネ。
internal-wordpress-server.invalid は HTTP 通信のみで、HTTPS は喋れません。
失敗4)
個人的に、Wordpress の PHP に設定以外の項目をごちゃごちゃ書くのは、
スマートではなく好みではない。
ので、
Google 先生に再度、
「HTTP のヘッダーだけでなく HTMLコンテンツも Reverse Proxy する方法はないの?」
と問い合わせてみました。
すると、Apache HTTPD 2.4 には mod_proxy_html があるよ
- https://httpd.apache.org/docs/2.4/mod/mod_proxy_html.html
- http://apache.webthing.com/mod_proxy_html/
と回答いただきました。
そこで、上記失敗3)の設定は元に戻して、
Reverse Proxy 機能を提供する My Web Server で以下の設定(ProxyHTMLEnable,ProxyHTMLURLMap)を追加しました。
ProxyRequests Off
ProxyPass "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverse "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverseCookieDomain internal-wordpress-server.invalid My-Web-Server.invalid
ProxyPassReverseCookiePath / /
ProxyHTMLEnable On
ProxyHTMLURLMap http://internal-wordpress-server.invalid/ /blog/
すると、firefox 君が
「内容符号化 (Content-Encoding) に問題があります
* 不正または不明な形式で圧縮されているため、ページを表示できません。」
と怒ってきました。
言い換えると、単純に Reverse Proxy しただけだと、HTML テキストは表示できたけど、ProxyHTMLEnable On で HTML テキストまで表示できなくなったのです。
何が違うのか…
ということで、HTML が表示できた場合と、できない場合の HTTP header を見比べてみました。
すると、
- HTML テキストだけが表示できた場合
GET /blog/ HTTP/1.1
Host: My-Web-Server.invalid
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, brHTTP/1.1 200 OK
Server: Apache
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Type: text/html; charset=UTF-8
Content-Length: 3950
- ProxyHTMLEnable On にして表示できなくなった場合
GET /blog/ HTTP/1.1
Host: My-Web-Server.invalid
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate, brHTTP/1.1 200 OK
Date: Fri, 30 Jun 2017 02:48:38 GMT
Server: Apache
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Content-Length: 5479
と、同じ HTML テキストを gzip 圧縮しただけなはずなのに、
Content-Lnegth が違っている…
ということで、
「WordPress サーバが Reverse Proxy に転送した HTML テキストは gzip 圧縮しており、
更に Reverse Proxy が Client に送信したコンテンツデータは二重に gzip 圧縮している。」
という仮説が立てられます。
仮説が正しいかどうかは、
WordPress サーバがコンテンツを圧縮しないで応答する。
ようにしてみれば、確認できるはずです。
実際にやってみたら、仮説は正解でした。
成功事例1)
WordPress サーバから送信するコンテンツを圧縮しないようにしたら、
外部 client からも閲覧できるようになりました。
その際の設定は、次のとおりです。
- My Web Server (Reverse Proxy) の設定
ProxyRequests Off
ProxyPass "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverse "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverseCookieDomain internal-wordpress-server.invalid My-Web-Server.invalid
ProxyPassReverseCookiePath / /
ProxyHTMLEnable On
ProxyHTMLURLMap http://internal-wordpress-server.invalid/ /blog/
# /etc/apache2/mods-enabled/deflate.conf のシンボリックリンクを消すだけでもOKですね。
#
# # these are known to be safe with MSIE 6
# AddOutputFilterByType DEFLATE text/html text/plain text/xml
#
# # everything else may cause problems with MSIE 6
# AddOutputFilterByType DEFLATE text/css
# AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
# AddOutputFilterByType DEFLATE application/rss+xml
# AddOutputFilterByType DEFLATE application/xml
#
これだと、イントラネットの Client からアクセスした場合も、
コンテンツが圧縮されなくなります。
実害はあまりないのですが、もうちょっとスマートにしたいですね。
ということで、Reverse Proxy した場合だけ圧縮しないように
する方法を調べたら、こんなヒントがありました。
方法としては、SetEnvIfNoCase ディレクティブで、
「 HTTP ヘッダ内で X-Forwarded-Host が設定されていたら、圧縮しない」
ようにしたら、うまくできました。
その設定は、以下の「最終成功時の設定」に書いておきます。
お礼>
失敗事例を全部読んでくださった皆様へ
貴重なお時間を割いていただき、ありがとうございました。
=================< 最終成功時の設定 >==================
ということで、ずらずらと途中経過を書きましたが、
結論としては 公開用Webサーバ (My Web Server) では
- Request Header を Reverse Proxy した上で、
- コンテンツ内も Reverse Proxy して URI を書き換え
内部の WordPress サーバでは、
- Reverse Proxy サーバからのリクエストに対してはコンテンツを圧縮しない
ように設定すると、成功しました。
- My Web Server (Reverse Proxy) の設定
ProxyRequests Off
ProxyPass "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverse "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverseCookieDomain internal-wordpress-server.invalid My-Web-Server.invalid
ProxyPassReverseCookiePath / /
ProxyHTMLEnable On
ProxyHTMLURLMap http://internal-wordpress-server.invalid/ /blog/
# these are known to be safe with MSIE 6
AddOutputFilterByType DEFLATE text/html text/plain text/xml# everything else may cause problems with MSIE 6
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/xml
SetEnvIfNoCase X-Forwarded-Host .+$ no-gzip dont-vary
実例は、 https://grasso.homeip.net/blog/ にて公開しています…
※ 2017.7.8 追記
Reverse Proxy サーバ側で以下のように "SetOutputFilter INFLATE"を追記すると、
WordPress 側での "SetEnvIfNoCase" 設定は不要になります。
(但し、Reverse Proxy 側では「inflate -> deflate」処理をする可能性があり、負荷が掛ります…)
ProxyRequests Off
ProxyPass "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverse "/blog/" "http://internal-wordpress-server.invalid/"
ProxyPassReverseCookieDomain internal-wordpress-server.invalid My-Web-Server.invalid
ProxyPassReverseCookiePath / /
SetOutputFilter INFLATE
ProxyHTMLEnable On
ProxyHTMLURLMap http://internal-wordpress-server.invalid/ /blog/