2026年5月20日
2026年5月20日
WordPressの.htaccess設定:基本ルール・リダイレクト・アクセス制限・キャッシュ
.htaccessとWordPressの関係
.htaccess は Apache がディレクトリごとに読み込む設定ファイルです。WordPress のパーマリンク(/sample-post/ のような URL)は、存在しないファイルへのリクエストを index.php に回す mod_rewrite のルールで動いています。このルールが無い、または Apache が .htaccess を読まない設定になっていると、トップページ以外が 404 になります。
この記事は Apache 2.4 を前提にします(2026年10月時点の主要ディストリビューションが提供している系列です)。Nginx は .htaccess を読まないため、同じことはサーバーの設定ファイルに書きます。
WordPress標準の.htaccess
単一サイトを公開ディレクトリ直下に置いた場合、WordPress が書き込む標準ルールは次のとおりです(公式ドキュメント の Basic WP)。
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
各行の役割は次のとおりです。
| 行 | 役割 |
|---|---|
RewriteRule .* - [E=HTTP_AUTHORIZATION:...] |
Authorization ヘッダーを PHP に渡す(アプリケーションパスワードによる REST API 認証などで使う) |
RewriteRule ^index\.php$ - [L] |
index.php 自体はそのまま処理する |
RewriteCond %{REQUEST_FILENAME} !-f / !-d |
実在するファイル・ディレクトリ(画像や CSS など)は書き換えない |
RewriteRule . /index.php [L] |
それ以外をすべて index.php に渡す |
WordPress を /blog/ のようなサブディレクトリに置いた場合は、RewriteBase /blog/ と RewriteRule . /blog/index.php [L] になります。
# BEGIN WordPress から # END WordPress までは WordPress が書き換える範囲です。パーマリンク設定を保存したときなどに上書きされるため、自分で足すルールはこの範囲の外(通常は上)に書きます。
.htaccessを再生成する
管理画面から
「設定」→「パーマリンク」で何も変えずに「変更を保存」を押すと、WordPress が .htaccess を書き直します。ファイルに書き込めない場合は、画面の下に書き込むべきルールが表示されるので、それを手作業で .htaccess に貼り付けます。
WP-CLIから
wp rewrite flush --hard
--hard は .htaccess も更新するオプションで、単一サイトでのみ動きます。WP-CLI から .htaccess を生成するには、WP-CLI に mod_rewrite が使えることを伝える設定が必要です(wp rewrite flush の公式説明)。WordPress のルートに wp-cli.yml を置き、次のように書きます。
apache_modules:
- mod_rewrite
パーミッション
.htaccess は通常 644 で十分です。Web サーバーのユーザーに書き込み権限を与えると WordPress が自動で更新できますが、侵入されたときに書き換えられる危険も増えます。書き込みを許さず、管理画面に表示されたルールを手で反映する運用でも問題ありません。
ls -l /var/www/html/.htaccess
Apacheが.htaccessを読む設定にする
.htaccess に書いても効かない場合、まずサーバー側の設定を確認します。Ubuntu の /etc/apache2/apache2.conf では /var/www/ に AllowOverride None が設定されており、この状態では .htaccess は無視されます。
バーチャルホストの設定(例: /etc/apache2/sites-available/000-default.conf)に次を追加します。
<Directory /var/www/html>
AllowOverride All
</Directory>
mod_rewrite を有効にし、構文を確認してから設定を読み込み直します。
sudo a2enmod rewrite
sudo apache2ctl configtest
sudo systemctl reload apache2
AllowOverride All ではなく必要な分類だけを許可する場合、この記事で使う命令の分類は次のとおりです(Apache 公式マニュアルの Override 欄)。
| 使う命令 | 必要な AllowOverride |
|---|---|
RewriteEngine / RewriteRule、Header |
FileInfo |
Require |
AuthConfig |
Options |
Options |
ExpiresActive / ExpiresByType |
Indexes |
共用レンタルサーバーではこの設定を変えられないことが多く、通常は .htaccess が有効な状態で提供されています。
リダイレクトを設定する
リダイレクトは # BEGIN WordPress より上に書きます。mod_rewrite と Redirect(mod_alias)を混ぜると処理順が分かりにくくなるため、ここでは RewriteRule にそろえます。example.com は自分のドメインに置き換えてください。
<IfModule mod_rewrite.c>
RewriteEngine On
# www あり → www なし(HTTPS へ1回で移す)
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]
# HTTP → HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# 個別ページの移転
RewriteRule ^old-page/?$ /new-page/ [R=301,L]
# カテゴリのスラッグ変更(配下のURLもまとめて移す)
RewriteRule ^category/old-cat/(.*)$ /category/new-cat/$1 [R=301,L]
</IfModule>
注意点:
- 「設定」→「一般」の「WordPress アドレス」「サイトアドレス」も、リダイレクト先と同じ形(
https://、www の有無)にそろえます。食い違うとリダイレクトがループします。 - ロードバランサーや CDN で HTTPS を終端している構成では、Apache には HTTP で届くため
%{HTTPS} offが常に成り立ち、ループします。その場合は HTTPS への転送を CDN 側で行うか、構成に合ったヘッダー(X-Forwarded-Protoなど)で判定します。 - 301 はブラウザにキャッシュされます。試すときは 302 で動作を確認してから 301 に変えると、間違えたときに戻しやすくなります。
アクセスを制限する
Apache 2.4 では Order / Deny from ではなく Require を使います(Order 系は 2.2 の書き方で、mod_access_compat が無いと 500 エラーになります)。
# wp-config.php への直接アクセスを拒否
<Files wp-config.php>
Require all denied
</Files>
# ディレクトリ一覧を表示しない
Options -Indexes
.htaccess 自体は、Ubuntu などの既定設定(apache2.conf の <FilesMatch "^\.ht">)で外部から読めないようになっています。
xmlrpc.phpを止める
XML-RPC を使っていなければ、総当たり攻撃の入口を減らすために止められます。Jetpack の一部機能や、XML-RPC で投稿する外部ツールを使っている場合は止めないでください。
<Files xmlrpc.php>
Require all denied
</Files>
uploadsでPHPを実行させない
<Directory> は .htaccess の中では使えません(サーバー設定とバーチャルホストでのみ有効)。アップロードフォルダーで PHP を止めるには、wp-content/uploads/.htaccess を作って次を書きます。
<FilesMatch "\.(?i:php|phtml|phar)$">
Require all denied
</FilesMatch>
詳しくは アップロードフォルダーでのPHP実行を.htaccessで止める方法 を参照してください。
画像の直リンクを防ぐ
自サイト以外のページに画像を埋め込まれるのを防ぎます。リファラーが空のアクセス(直接開いた場合や、リファラーを送らない設定のブラウザ)は許可しています。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com/ [NC]
RewriteRule \.(jpe?g|png|gif|webp)$ - [F,NC]
</IfModule>
検索エンジンの画像検索や SNS のプレビューでも画像が出なくなることがあるため、必要に応じて許可するドメインを追加します。
ブラウザキャッシュと圧縮
静的ファイルにキャッシュ期限を付けると、再訪時の読み込みが減ります。mod_expires と mod_deflate が有効か確認し、無ければ有効にします。
apache2ctl -M | grep -E 'expires|deflate|headers'
sudo a2enmod expires deflate
sudo systemctl reload apache2
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType image/jpeg "access plus 6 months"
ExpiresByType image/png "access plus 6 months"
ExpiresByType image/webp "access plus 6 months"
ExpiresByType image/svg+xml "access plus 6 months"
ExpiresByType font/woff2 "access plus 1 year"
</IfModule>
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/css
AddOutputFilterByType DEFLATE application/javascript application/json
AddOutputFilterByType DEFLATE application/xml image/svg+xml
</IfModule>
- HTML には期限を付けていません。記事を更新してもブラウザに古いページが残るのを避けるためです。
- WordPress はテーマやプラグインの CSS・JS に
?ver=を付けて読み込むため、バージョンが上がれば新しいファイルが取得されます。テーマを直接編集してバージョンを変えない場合は、期限を短めにします。 - JPEG・PNG・WebP・WOFF2 はすでに圧縮された形式なので、DEFLATE の対象に入れません。
- キャッシュ系のプラグインが同じ内容を
.htaccessに書き込むことがあります。二重に書かないよう、先に既存の記述を確認してください。
変更後に確認する
apache2ctl configtest はサーバー設定ファイルの構文を確かめるもので、.htaccess は検査しません。.htaccess の誤りはアクセスしたときに 500 エラーとして現れます。
変更する前に複製を取っておきます。
cp /var/www/html/.htaccess /var/www/html/.htaccess.bak
変更後はヘッダーで結果を確かめます。
# リダイレクト先とステータス
curl -sI http://www.example.com/ | grep -iE '^(HTTP|location)'
# キャッシュ期限
curl -sI https://example.com/wp-includes/css/dist/block-library/style.min.css | grep -iE '^(cache-control|expires)'
# 拒否されること(403 になる)
curl -sI https://example.com/wp-config.php | head -n 1
500 エラーになったら Apache のエラーログを見ます。
sudo tail -n 50 /var/log/apache2/error.log
Invalid command '...', perhaps misspelled or defined by a module not included in the server configuration と出る場合は、その命令のモジュールが無効か、綴りが誤っています。not allowed here と出る場合は、AllowOverride で許可されていない命令か、.htaccess に書けない命令(<Directory> など)です。すぐに戻すときは、取っておいた複製で上書きします。
まとめ
- WordPress の標準ルールは
# BEGIN WordPress~# END WordPressの間にあり、自分のルールはその外に書く。 - 再生成は「設定」→「パーマリンク」の保存、または
wp-cli.ymlにapache_modulesを書いたうえでwp rewrite flush --hard。 - 効かないときは
AllowOverrideと mod_rewrite の有効化を確認する。 - アクセス制限は Apache 2.4 の
Requireで書き、<Directory>は.htaccessでは使わない。 .htaccessの誤りはconfigtestでは見つからないため、変更前に複製を取り、curl -Iとエラーログで確認する。
Apache の .htaccess 全般については Apacheの.htaccessの使い方 も参考になります。