2026年7月29日
2026年7月29日
Apache mod_proxy で接続できない場合の対処|503・502・504をエラーログから切り分ける
Apache の mod_proxy で裏のサーバーへ接続できないときは、ブラウザに出るステータス(503・502・504)と、Apache の error_log に出る「AH」から始まるメッセージを突き合わせると、原因をかなり絞り込めます。この記事では、まず症状とログの読み方を整理し、そのあと起こりやすい原因の順に「確かめ方」と「直し方」を並べます。設定を変える前には、該当の設定ファイルを複製してから作業してください。
まず症状とログを確認する
最初に見るのは2か所です。
- ブラウザ(または curl)で返るステータスコード
- Apache の error_log(Ubuntu/Debian は
/var/log/apache2/error.log、RHEL 系は/var/log/httpd/error_logが多い)
ログが少なすぎて原因が見えない場合は、該当の VirtualHost に次の1行を足して再読み込みすると、プロキシ関連だけ詳しく出せます。調べ終わったら元に戻してください。
LogLevel warn proxy:debug proxy_http:debug
あわせて、プロキシを動かしているサーバー上から転送先へ直接リクエストを送ってみます。これで「転送先そのものが応答しない」のか「Apache の設定の問題」なのかが分かれます。
# Apache を動かしているサーバーで実行する
curl -sv http://127.0.0.1:8080/ -o /dev/null
# 転送先が別サーバーの場合
curl -sv http://10.0.0.11:8080/ -o /dev/null
curl でも応答が無ければ転送先側、curl では応答があるのに Apache 経由だけ失敗するなら Apache 側の設定やセキュリティ機構を疑います。
症状ごとの見当
| 症状 | よく出るログの傾向 | まず疑うこと |
|---|---|---|
| 503 Service Unavailable | 接続に失敗した旨と、ワーカーを一時的に無効化した旨 | 転送先が止まっている、ポート違い、SELinux |
| 500 Internal Server Error | 有効なプロトコルハンドラーが無い旨 | mod_proxy_http などのサブモジュール未読み込み |
| 502 Proxy Error | 転送先からのステータス行を読めなかった旨 | 転送先が接続を途中で切った、使い回し接続の不整合 |
| 504 Gateway Timeout | タイムアウトの旨 | 転送先の処理が遅い、ProxyTimeout が短い |
メッセージ番号(AH00957 など)は版によって変わることがあるので、番号ではなく文面の意味で判断してください。
原因1:転送先が動いていない・ポートが違う
いちばん多い原因です。503 とともに、接続先への接続に失敗した旨(AH00957 など)と、そのワーカーを一定時間無効にした旨(AH00959 など)が出ます。
確かめ方は、転送先のサーバーで待ち受けを見ることです。
sudo ss -tlnp | grep 8080
何も出なければアプリや PHP-FPM、Node.js などが止まっているか、別のポートで待ち受けています。127.0.0.1 だけで待ち受けている場合、別サーバーの Apache からは届きません。転送先を起動し直すか、ProxyPass のポートを実際の待ち受けに合わせます。サーバーが分かれている場合は、ufw・firewalld・クラウドのセキュリティグループで Apache サーバーからの通信が許可されているかも確認します。
注意したいのは、mod_proxy が接続に失敗したワーカーを一定時間(既定では60秒)使わなくなる点です。転送先を直した直後もしばらく 503 が続くことがあります。検証中は ProxyPass に retry=0 を付けると、すぐ再試行されます。
ProxyPass "/app/" "http://127.0.0.1:8080/" retry=0
ProxyPassReverse "/app/" "http://127.0.0.1:8080/"
原因2:SELinux が接続を止めている
RHEL・AlmaLinux・Rocky Linux などで、curl では届くのに Apache 経由だけ 503 になる場合は SELinux を疑います。error_log では、接続失敗のメッセージに「Permission denied」が添えられます。
getenforce
sudo ausearch -m avc -ts recent | grep httpd
拒否が記録されていれば、Apache にネットワーク接続を許可するブール値を有効にします。SELinux 自体を無効にするのは避けてください。
sudo setsebool -P httpd_can_network_connect 1
原因3:必要なモジュールが読み込まれていない
ProxyPass を書いても mod_proxy_http が無いと、HTTP の転送先を扱えません。このとき error_log には「有効なプロトコルハンドラーが無い」「サブモジュールを LoadModule で読み込むように」という趣旨のメッセージ(AH01144 など)が出て、ブラウザには 500 が返ります。
# 読み込まれているモジュールの確認
apachectl -M | grep -i proxy
# Ubuntu/Debian での有効化
sudo a2enmod proxy proxy_http
sudo apachectl configtest && sudo systemctl reload apache2
WebSocket を通す場合は mod_proxy_wstunnel、または Apache 2.4.47 以降なら ProxyPass の upgrade=websocket が別に必要です。RHEL 系では /etc/httpd/conf.modules.d/ 配下のファイルで読み込みが管理されています。
原因4:HTTPS の転送先で SSLProxyEngine が無い
ProxyPass の転送先を https:// にしているのに、VirtualHost に SSLProxyEngine on が無いと接続できません。error_log には SSL プロキシが要求されたが有効になっていない旨(AH01961 など)が出ます。
SSLProxyEngine on
ProxyPass "/" "https://backend.internal/"
ProxyPassReverse "/" "https://backend.internal/"
転送先が自己署名証明書の場合、証明書の検証で失敗します。検証を切る設定(SSLProxyVerify none や SSLProxyCheckPeerName off)で回避する例を見かけますが、本番では通信の正当性を確かめられなくなります。内部 CA の証明書を SSLProxyCACertificateFile で指定する方法を優先してください。
原因5:502 が断続的に出る
毎回ではなく、ときどき 502 になる場合は、Apache が使い回そうとした接続を転送先がすでに閉じていることがよくあります。ログには、転送先からステータス行を読めなかった旨(AH01102 など)が出ます。
対処は次の順で試します。
- 転送先のキープアライブのタイムアウトを、Apache 側より長くする
- ProxyPass に
disablereuse=Onを付け、接続の使い回しをやめる(接続数は増えます) - 転送先のアプリのログで、処理中に落ちていないか(メモリ不足や PHP-FPM の再起動など)を確認する
原因6:504 やタイムアウト
重い処理(インポート、バックアップ、外部 API 待ち)で 504 になる場合は、転送先の処理時間に対して Apache の待ち時間が足りていません。ProxyTimeout、または ProxyPass の timeout= で延ばせます。
ProxyTimeout 120
ただし、待ち時間を延ばすほど接続を長く抱えることになります。処理自体を短くする、非同期にするといった根本対策と並行して検討してください。
接続はできるが表示がおかしい場合
接続自体はできていても、リダイレクトが内部アドレスに飛ぶ、CSS が読み込まれない、ログインがループするといった症状は、ヘッダーの受け渡しが原因です。
ProxyPreserveHost Onが無く、転送先に元のホスト名が届いていないProxyPassReverseが無く、転送先が返したリダイレクトの Location が書き換えられていない- ProxyPass の左右で末尾の
/がそろっていない(/app/とhttp://backend/のように両方に付けるか、両方から外す) - WordPress の場合、HTTPS 判定のために
X-Forwarded-Protoを渡し、wp-config.php 側で受け取る設定が必要
直したあとの確認
設定を変えたら、構文検査を通してから再読み込みします。再起動ではなく再読み込みにすると、接続中の利用者への影響を抑えられます。
sudo apachectl configtest
sudo systemctl reload apache2 # RHEL 系は httpd
モジュール名やログの文面は Apache の版やディストリビューションで差があります。主流は 2.4 系です(2026年10月現在)。本番で試す前に、できればステージングで同じ設定を再現して確認してください。
まとめ
- ステータスコードと error_log の文面を対応させ、curl で転送先へ直接届くかを先に確かめます。
- 503 は転送先の停止・ポート違い・SELinux、500 はモジュール不足、502 は接続の使い回し、504 は待ち時間不足が典型です。
- 失敗したワーカーはしばらく使われないため、直後の 503 は
retry=0で切り分けます。 - 証明書の検証を切る回避策は避け、内部 CA を指定します。
- 変更前に設定ファイルを複製し、構文検査を通してから再読み込みします。