このページでは、Apache HTTP Server を利用した Reverse Proxy の仕組みと、一般的な構築方法を整理する。
Web システムでは、利用者のブラウザから送られてくる HTTP / HTTPS リクエストを、必ずしもアプリケーションサーバーが直接受け取るとは限らない。多くの場合、まず Web サーバーが入口となり、その背後で動作するアプリケーションへ処理を渡す構成が採用されている。
このような構成では、外部からのアクセスを Web サーバーが受け取り、内部のサーバーへリクエストを転送する仕組みが必要となる。この役割を持つ仕組みを Reverse Proxy と呼ぶ。
本ページでは、Reverse Proxy の基本的な動作を理解したうえで、Apache HTTP Server を利用した一般的な構築方法について整理する。
Reverse Proxy は、利用者からのアクセスを内部のサーバーへ取り次ぐ仕組みである。利用者が Web サイトへアクセスすると、ブラウザは HTTP または HTTPS を使用して Web サーバーへリクエストを送信する。このときブラウザが接続しているのは Apache HTTP Server であり、内部で動作しているアプリケーションではない。
Apache は受け取ったリクエストを内部のアプリケーションサーバーへ転送し、アプリケーションはそのリクエストを処理して結果を Apache へ返す。Apache は受け取ったレスポンスを利用者へ返すことで、ブラウザには通常の Web サーバーとして応答しているように見える。
このような構成では、利用者からは Apache が Web サーバーとして見える一方で、実際の処理は内部のアプリケーションが行っている。そのため、アプリケーションサーバーをインターネットへ直接公開する必要がなくなり、セキュリティや運用の面で管理しやすい構成を実現できる。
客は料理を注文するとき、直接キッチンへ行くわけではない。まず店員に注文を伝え、店員がその内容をキッチンへ取り次ぐ。キッチンで料理が完成すると、店員がそれを受け取り、客のテーブルまで運ぶ。
客 → 利用者(Browser)
店員 → Reverse Proxy(Apache)
キッチン → アプリケーションサーバー
Web アプリケーションは、必ずしも 80 番ポートや 443 番ポートで直接待ち受けるわけではない。多くの場合、アプリケーションはローカルホスト上の任意ポートで動作しており、たとえば Node.js 系のアプリケーションでは 127.0.0.1:3000 のようなポートで待ち受ける構成がよく見られる。
しかし、このような構成のままでは利用者がポート番号を指定してアクセスする必要があり、HTTPS の証明書管理もアプリケーション側で個別に行うことになる。
そこで Apache HTTP Server を前段に配置し、利用者からの HTTPS 通信を Apache が受け付け、内部で動作しているアプリケーションへリクエストを転送する構成を採用する。
この構成にすることで、次の利点がある。
Apache で Reverse Proxy を利用するには Proxy モジュールが有効になっている必要がある。
httpd -M | grep proxy
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
ProxyPass /socket.io/ ws://127.0.0.1:3000/socket.io/
ProxyPassReverse /socket.io/ ws://127.0.0.1:3000/socket.io/
利用者のブラウザが送信した Host ヘッダを、そのままバックエンドアプリケーションへ渡す設定である。
この設定を有効にすると、利用者がアクセスしたドメイン名(Host ヘッダ)が、そのままバックエンドアプリケーションへ渡される。
Reverse Proxy 構成では、バックエンドアプリケーションから見ると接続元は Apache になる。そのため元のアクセス情報をアプリケーションへ伝える目的で、Apache がヘッダを追加する。
X-Forwarded-Proto
元の通信が HTTP か HTTPS かを示す。
X-Forwarded-Port
利用者が接続したポート番号を示す。
Apache が受け取ったリクエストをバックエンドアプリケーションへ転送する設定である。
ProxyPass / http://127.0.0.1:3000/
この設定では Apache が受け取った / 以下のリクエストを 127.0.0.1:3000 で動作しているアプリケーションへ転送する。
バックエンドアプリケーションが返すレスポンスヘッダを書き換える設定である。
アプリケーションが内部アドレスを返す場合でも、ブラウザには Apache の URL が返るように調整する。
リアルタイム通信を行うアプリケーションでは WebSocket が使用される場合がある。
その場合は ws:// を指定して WebSocket 通信を転送する。
ProxyPass /socket.io/ ws://127.0.0.1:3000/socket.io/
apachectl configtest
systemctl restart httpd
Reverse Proxy が正常に動作しているか確認する。
確認は次の順序で行う。
・バックエンドアプリケーション確認
・Apache 経由確認
まず、バックエンドアプリケーションが直接応答することを確認する。
curl -I http://127.0.0.1:3000
実行例
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 20107
HTTP 200 が返れば、バックエンドアプリケーションは正常に動作している。
次に Apache を経由してアクセスする。
curl -I https://example.local
実行例
HTTP/2 200
server: Apache
content-type: text/html; charset=utf-8
content-length: 20107
HTTP 200 が返れば Apache がリクエストを受け取り、
内部アプリケーションへ転送できている。
次の条件が確認できれば Reverse Proxy は正常に動作している。
・バックエンドが HTTP 200 を返す
・Apache 経由でも HTTP 200 が返る
・レスポンスヘッダが一致している
今回の確認結果では次のヘッダが一致している。
Content-Type: text/html; charset=utf-8
Content-Length: 20107
ETag: W/"4e8b-g/TexQbzug5uZNSi5FZaSCupbcY"
Apache 経由でも同じレスポンスが返っているため Apache が内部アプリケーションへリクエストを転送していることが確認できる。
つまり Reverse Proxy は正常に動作している。
バックエンドアプリケーションが停止している場合、Apache は次のエラーを返す。
502 Bad Gateway
または
503 Service Unavailable
この挙動が確認できる場合、Apache は Reverse Proxy として動作している。
Reverse Proxy は、利用者からのアクセスを Web サーバーが受け取り、内部で動作しているアプリケーションサーバーへリクエストを転送する仕組みである。Apache HTTP Server では ProxyPass と ProxyPassReverse を利用することで、このような内部アプリケーションへのリクエスト転送を構成できる。
この仕組みを利用することで、アプリケーションサーバーをインターネットへ直接公開する必要がなくなり、Web サービスをより安全で管理しやすい構成で公開することができる。
Reverse Proxy を実運用で利用する場合、通信の暗号化が重要となる。
次のページでは Apache で TLS / HTTPS を構成する方法を整理する。
[TLS / HTTPS]