環境情報
- Webサーバ: Apache 2.4.x (本番/テスト共通)
- ドメイン構成: サブドメイン + パスベースのリダイレクト
- デプロイ方式: FTP / rsync / CIパイプライン
- 管理対象ファイル:
.htaccess,index.php,wp-config.php等
はじめに:見落としがちな「.htaccessの環境差分」
筆者は先日、本番環境へのデプロイ後に突如として発生したリダイレクトループに悩まされた。原因は、テスト環境と本番環境で.htaccessの設定が異なっていたことだ。テストでは正常に動作していたリダイレクトルールが、本番サーバのディレクトリ構造やモジュール有効状態によって無限ループを引き起こした。
このようなトラブルは、.htaccessに限らず、php.iniやnginx.confなど環境依存の設定ファイル全般で起こりうる。本記事では、具体的な事例をもとに、デプロイ前に必ず確認すべき「差分チェックリスト」の作成手順と、自動化による予防策を紹介する。
事例:本番環境で発生したリダイレクトループの詳細
発生した状況
- テスト環境:
http://test.example.com/sub/→https://test.example.com/sub/にリダイレクト(末尾スラッシュ付き) - 本番環境:
http://example.com/sub→https://example.com/sub/にリダイレクト(末尾スラッシュ追加+HTTPS)
テスト環境の.htaccess:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
本番環境の.htaccess(間違った状態):
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{REQUEST_URI} !^/sub/
RewriteRule ^sub$ /sub/ [R=301,L]
一見問題なさそうだが、本番環境ではsubディレクトリ配下にindex.phpが存在し、かつDirectoryIndexの設定が異なっていた。その結果、/sub/へのリダイレクトが再度/subに書き換えられ、ループが発生した。
ハマりポイント
- テスト環境では
DirectoryIndexの設定がindex.htmlのみだったため、リダイレクトが正しく終了した。 - 本番環境では
DirectoryIndex index.phpが優先され、/sub/へのアクセスが内部的に/sub/index.phpにマッピングされ、さらに別のRewriteRuleが発動してループ。 - このようなモジュールやディレクティブの有効状態の違いは、
.htaccess単体では検出が難しい。
なぜ差分が生まれるのか:環境間の設定差異の原因
- 開発環境(ローカル)とステージング環境、本番環境でApacheのバージョンやモジュール構成が異なる
-
.htaccessがリポジトリ管理外(.gitignoreなど)で、手動で配置されるケース - デプロイスクリプトが
.htaccessを上書きしない設定になっている - 複数人開発で
.htaccessの変更履歴が追跡できていない
デプロイ前差分チェックリストの作り方(ステップバイステップ)
Step 1: チェック対象ファイルの列挙
まず、環境依存が発生しうる設定ファイルをリストアップする。例:
-
.htaccess(ルートおよびサブディレクトリ) -
wp-config.php(WordPressの場合) -
.env(環境変数ファイル) -
composer.json/package.json(依存関係) -
php.ini(カスタム設定がある場合)
Step 2: 環境ごとの設定値を比較するためのテンプレート作成
各ファイルについて、テスト環境と本番環境で共通の「基準値」を定義する。例えば:
| 設定項目 | テスト環境の値 | 本番環境の値(想定) | 差分チェック |
|---|---|---|---|
| RewriteBase | /test/ | / | 要確認 |
| HTTPS強制 | OFF→ON | 常にON | 要確認 |
| ベースURL | http://test.example.com | https://example.com | 要確認 |
| DirectoryIndex | index.html | index.php | 要確認 |
Step 3: 自動比較スクリプトの作成
シェルスクリプトで、デプロイ前に2つの環境のファイルをダウンロードしてdiffを取る。
#!/bin/bash
# diff_check.sh - テスト環境と本番環境の.htaccess差分チェック
TEST_URL="https://test.example.com/.htaccess"
PROD_URL="https://example.com/.htaccess"
TEMP_DIR=$(mktemp -d)
curl -s "$TEST_URL" > "$TEMP_DIR/test_htaccess"
curl -s "$PROD_URL" > "$TEMP_DIR/prod_htaccess"
if diff "$TEMP_DIR/test_htaccess" "$TEMP_DIR/prod_htaccess" > /dev/null; then
echo "OK: 差分なし"
else
echo "NG: 以下に差分があります"
diff "$TEMP_DIR/test_htaccess" "$TEMP_DIR/prod_htaccess"
fi
rm -rf "$TEMP_DIR"
注意:curlで.htaccessを取得するにはサーバ設定でAllowOverrideが適切に設定されている必要がある。実際には、リポジトリから直接比較するほうが安全。
Step 4: 重要な箇所だけを抜き出す正規表現チェック
全ての行を比較するのではなく、環境依存の項目(絶対パス、ドメイン名、ディレクトリ名)を抽出して比較する。
grep -E 'RewriteCond %{HTTP_HOST}|RewriteRule \^|RewriteBase' .htaccess
この結果を環境ごとに集約し、一致するか確認する。
よくある誤設定とその対策(FAQ形式)
Q1: RewriteBaseの設定が環境で異なる場合の対処法は?
A: RewriteBaseは相対パスに依存するため、環境ごとに動的に切り替える。可能ならRewriteBaseを使わず、フルパスRewriteRuleに統一する。
Q2: HTTPSリダイレクトでループが発生したが、なぜ?
A: リダイレクト先が再度リダイレクト条件を満たしてしまうケース。対策として、以下のように%{ENV:REDIRECT_STATUS}をチェックする。
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Q3: 本番だけ特定のRewriteRuleが効かない
A: モジュールmod_rewriteの有効状態、AllowOverrideの設定、.htaccessの配置場所(サブディレクトリに置かれているか)を確認。
チェックリストの実装例:CI/CDへの組み込み
GitHub ActionsなどのCIでプルリクエスト作成時に自動チェックする例。
# .github/workflows/htaccess-check.yml
name: Check .htaccess consistency
on: [pull_request]
jobs:
diff-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Compare with production template
run: |
if diff <(grep -v '^\s*#' .htaccess) <(curl -s ${{ secrets.PROD_BASE_URL }}/.htaccess) > /dev/null; then
echo "一致"
else
echo "差分があります"
exit 1
fi
ただし、本番サーバの.htaccessをcurlで取得するのはセキュリティ上問題があるため、実際はリポジトリ内に「本番用テンプレート」を別途管理する方法が推奨される。
総合的ベストプラクティス
-
.htaccessは必ずGit等でバージョン管理し、環境ごとの差分は環境変数やif文で吸収する。 - デプロイ前に「設定ファイル差分チェックリスト」を手順書として保持し、リリース担当者が確認する。
- CIに組み込めるチェックは自動化し、人の目はロジックの妥当性確認に集中する。
- ステージング環境は本番と可能な限り同一構成にする(Apacheのバージョン、PHPモジュール、拡張子の関連付けまで)。
- リダイレクトルールをデバッグするときは、
RewriteLog(またはLogLevel alert rewrite:trace6)を有効にし、実際の処理フローを追跡する。
まとめ
デプロイ前の一瞬の確認不足が、本番環境でのリダイレクトループという重大なインシデントにつながる。本記事で紹介したチェックリストの作成と自動化は、たった数分の手間で大きなトラブルを未然に防ぐ。特に.htaccessは「見えない設定」であるがゆえに、差分を見落としやすい。ぜひ今日から、デプロイフローに「設定ファイル差分チェック」のステップを追加してほしい。
この記事を書いた人
BENTEN Web Works — 業務自動化・システム開発のフリーランスエンジニアです。
GAS / Python / RPA を使った業務自動化や、Web制作・システム開発のご相談を承っています。
「こんなこと自動化できる?」というご質問だけでもお気軽にどうぞ。
👉 情シス代行サービス — 詳細・お問い合わせはこちら
🐦 X(旧Twitter) — 日々の知見を発信中