.htaccess ファイルは、Apache Web サーバーの最も強力な設定ツールの1つです。メインのサーバー設定を変更することなく、リダイレクト、HTTPS の強制、セキュリティヘッダーの設定、キャッシュの管理などを制御できます。この包括的な .htaccess リダイレクトチートシートは、あらゆる一般的なシナリオに対応した本番環境対応のコピペ可能なサンプルを提供します。
基本リダイレクト
リダイレクトは .htaccess ファイルの最も一般的な用途です。単一ページの移動、ディレクトリ全体の再構成、新しいドメインへの移行など、Apache の Redirect および RewriteRule ディレクティブで簡単に実現できます。SEO のリンク資産を新しい URL に移すために、常に 301(永久)リダイレクトを使用してください。
単一 URL のリダイレクト
# Redirect a single URL (301 permanent)
Redirect 301 /old-page.html https://example.com/new-page.html
# Using RewriteRule for more control
RewriteEngine On
RewriteRule ^old-page\.html$ /new-page.html [R=301,L]
# Redirect with pattern matching (e.g., old product URLs)
RewriteRule ^products/([0-9]+)\.html$ /shop/item/$1 [R=301,L]ディレクトリ全体のリダイレクト
# Redirect entire directory to new location
RedirectMatch 301 ^/blog/(.*)$ https://example.com/articles/$1
# Using RewriteRule (preserves subdirectory structure)
RewriteEngine On
RewriteRule ^blog/(.*)$ /articles/$1 [R=301,L]
# Redirect directory but keep filenames
RewriteRule ^old-folder/(.+)$ /new-folder/$1 [R=301,L]ドメイン間リダイレクト
# Redirect entire old domain to new domain
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?olddomain\.com$ [NC]
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]
# Redirect specific domain alias to primary domain
RewriteEngine On
RewriteCond %{HTTP_HOST} ^olddomain\.net$ [NC,OR]
RewriteCond %{HTTP_HOST} ^olddomain\.org$ [NC]
RewriteRule ^(.*)$ https://newdomain.com/$1 [R=301,L]HTTPS の強制
HTTPS の強制はセキュリティと SEO に不可欠です。Google は HTTPS をランキングシグナルとして使用し、モダンブラウザは安全でない HTTP 接続について警告します。これらのルールは mod_rewrite を使用してすべての HTTP トラフィックを HTTPS にリダイレクトします。
HTTP から HTTPS(www なし)
# Force HTTPS (redirect HTTP to HTTPS, non-www)
RewriteEngine On
# Redirect www to non-www
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
# Redirect HTTP to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]HTTP から HTTPS(www あり)
# Force HTTPS with www prefix
RewriteEngine On
# Redirect non-www to www
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
# Redirect HTTP to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]非 www + HTTPS を強制
# Force non-www + HTTPS in a single pass
# Works on shared hosting and most Apache setups
RewriteEngine On
# Handle both www removal and HTTPS enforcement together
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# Alternative: Using environment variables (some hosts)
# RewriteCond %{ENV:HTTPS} !on
# RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]末尾スラッシュの処理
末尾スラッシュの不一致は、SEO に悪影響を与える重複コンテンツの問題を引き起こします。検索エンジンは /about と /about/ を異なる URL として扱います。1つのスタイルを選び、サイト全体で一貫して適用してください。
末尾スラッシュを追加
# Add trailing slash to all URLs (except files with extensions)
RewriteEngine On
# Only apply to URLs without a file extension
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.[a-zA-Z0-9]{1,5}$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
# Simpler version (may cause issues with some file types)
# RewriteRule ^(.*[^/])$ $1/ [R=301,L]末尾スラッシュを削除
# Remove trailing slash from all URLs (except directories)
RewriteEngine On
# Do not remove trailing slash from actual directories
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [R=301,L]
# Remove trailing slash except for root URL
# RewriteCond %{REQUEST_URI} !^/$
# RewriteRule ^(.*)/$ /$1 [R=301,L]クエリ文字列の処理
クエリ文字列を含む URL のリダイレクトには特別な注意が必要です。デフォルトでは Apache は元のクエリ文字列をリダイレクト先に追加します。QSA(クエリ文字列追加)と ?(破棄)フラグを使用して、クエリパラメータを保持、破棄、変更できます。
クエリ文字列を保持してリダイレクト
# Redirect preserving the original query string (default behavior)
# /search?q=test -> /find?q=test
RewriteEngine On
RewriteRule ^search$ /find [R=301,L]
# Redirect and APPEND additional query parameters (QSA flag)
# /page?id=5 -> /new-page?id=5&ref=old
RewriteRule ^page$ /new-page?ref=old [R=301,L,QSA]
# Match specific query string and redirect
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^product\.php$ /products/%1? [R=301,L]クエリ文字列を破棄してリダイレクト
# Redirect and DISCARD all query parameters
# /old-page?any=params -> /new-page (clean URL)
RewriteEngine On
RewriteRule ^old-page$ /new-page? [R=301,L]
# The trailing ? strips the query string
# Discard specific query parameters only
# /page?utm_source=x&id=5 -> /page?id=5 (strip tracking params)
RewriteCond %{QUERY_STRING} (^|&)utm_[^&]*
RewriteRule ^(.*)$ /$1? [R=301,L]クエリパラメータを変更してリダイレクト
# Rewrite query parameter to path segment
# /index.php?page=about -> /about
RewriteEngine On
RewriteCond %{QUERY_STRING} ^page=(.+)$
RewriteRule ^index\.php$ /%1? [R=301,L]
# Rewrite path segment to query parameter
# /category/electronics -> /shop.php?cat=electronics
RewriteRule ^category/([a-zA-Z0-9-]+)$ /shop.php?cat=$1 [L]
# Rename a query parameter
# /search?q=test -> /search?query=test
RewriteCond %{QUERY_STRING} ^q=(.+)$
RewriteRule ^search$ /search?query=%1 [R=301,L]カスタムエラーページ
カスタムエラーページは、汎用的なサーバーエラーの代わりに有用な情報を提供することでユーザー体験を向上させます。ErrorDocument ディレクティブで任意の HTTP ステータスコードのカスタムページを定義できます。
# Custom error pages
# Place error page files in your document root
# 404 Not Found - page does not exist
ErrorDocument 404 /errors/404.html
# 403 Forbidden - access denied
ErrorDocument 403 /errors/403.html
# 500 Internal Server Error
ErrorDocument 500 /errors/500.html
# 401 Unauthorized - authentication required
ErrorDocument 401 /errors/401.html
# 503 Service Unavailable - maintenance mode
ErrorDocument 503 /errors/maintenance.html
# You can also use inline messages (not recommended for production)
# ErrorDocument 404 "Page not found. Please check the URL."
# Or redirect to an external URL
# ErrorDocument 404 https://example.com/not-found
# ── Maintenance mode (redirect all traffic to maintenance page) ──
# Uncomment during maintenance, recomment when done
# RewriteEngine On
# RewriteCond %{REMOTE_ADDR} !^123\.456\.789\.000$ # Allow your IP
# RewriteCond %{REQUEST_URI} !/errors/maintenance.html$ [NC]
# RewriteCond %{REQUEST_URI} !\.(css|js|png|jpg|gif|ico)$ [NC]
# RewriteRule ^(.*)$ /errors/maintenance.html [R=503,L].htaccess によるセキュリティヘッダー
HTTP セキュリティヘッダーは、クリックジャッキング、クロスサイトスクリプティング(XSS)、コンテンツインジェクションなどの一般的な攻撃からサイトを保護します。mod_headers の有効化が必要です。
# Security headers via .htaccess
# Requires mod_headers to be enabled: a2enmod headers
<IfModule mod_headers.c>
# X-Frame-Options: Prevent clickjacking by blocking iframes
# Options: DENY | SAMEORIGIN | ALLOW-FROM uri
Header always set X-Frame-Options "SAMEORIGIN"
# X-Content-Type-Options: Prevent MIME-type sniffing
Header always set X-Content-Type-Options "nosniff"
# X-XSS-Protection: Enable browser XSS filter (legacy)
Header always set X-XSS-Protection "1; mode=block"
# Referrer-Policy: Control referrer information
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Content-Security-Policy: Control resource loading
# Customize the sources based on your site's needs
Header always set Content-Security-Policy "default-src 'self'; \
script-src 'self' 'unsafe-inline' https://cdn.example.com; \
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; \
img-src 'self' data: https:; \
font-src 'self' https://fonts.gstatic.com; \
connect-src 'self' https://api.example.com; \
frame-ancestors 'self';"
# Strict-Transport-Security (HSTS): Force HTTPS for 2 years
# Only add this if your site fully supports HTTPS
Header always set Strict-Transport-Security \
"max-age=63072000; includeSubDomains; preload"
# Permissions-Policy: Disable unused browser features
Header always set Permissions-Policy \
"camera=(), microphone=(), geolocation=(), interest-cohort=()"
# Remove X-Powered-By header (hides PHP/server version)
Header unset X-Powered-By
Header always unset X-Powered-By
</IfModule>
# Hide Apache version in server headers
ServerSignature Offブラウザキャッシュルール
ブラウザキャッシュは、静的アセットをローカルに保存するようブラウザに指示し、リピーターのページ読み込み時間を大幅に改善します。mod_expires モジュールが Cache-Control と Expires ヘッダーを自動設定します。
# Browser caching with mod_expires
# Enable the module: a2enmod expires
<IfModule mod_expires.c>
ExpiresActive On
# Default expiration: 1 month
ExpiresDefault "access plus 1 month"
# HTML files: short cache (content changes frequently)
ExpiresByType text/html "access plus 1 hour"
# CSS and JavaScript: long cache (use fingerprinted filenames)
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType text/javascript "access plus 1 year"
# Images: cache for 1 month
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/webp "access plus 1 month"
ExpiresByType image/avif "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 year"
# Fonts: cache for 1 year
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType font/woff "access plus 1 year"
ExpiresByType font/ttf "access plus 1 year"
ExpiresByType application/font-woff2 "access plus 1 year"
ExpiresByType application/font-woff "access plus 1 year"
# JSON/XML data: short cache
ExpiresByType application/json "access plus 1 hour"
ExpiresByType application/xml "access plus 1 hour"
# PDF and documents
ExpiresByType application/pdf "access plus 1 month"
</IfModule>
# Alternative: Cache-Control headers with mod_headers
<IfModule mod_headers.c>
# Immutable cache for fingerprinted assets
<FilesMatch "\.(js|css)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
# Short cache for HTML
<FilesMatch "\.html$">
Header set Cache-Control "public, max-age=3600, must-revalidate"
</FilesMatch>
# No cache for dynamic content
<FilesMatch "\.(php|cgi)$">
Header set Cache-Control "no-store, no-cache, must-revalidate"
</FilesMatch>
</IfModule>Gzip / Brotli 圧縮
圧縮により転送レスポンスのサイズを 60-90% 削減し、ページ読み込み時間を大幅に改善できます。Apache は Gzip(mod_deflate)と Brotli(mod_brotli、Apache 2.4.26+)の両方をサポートしています。
Gzip 圧縮(mod_deflate)
# Gzip compression using mod_deflate
# Enable the module: a2enmod deflate
<IfModule mod_deflate.c>
# Compress text-based content types
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/atom+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/ld+json
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE font/woff
AddOutputFilterByType DEFLATE font/woff2
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
# Do not compress images (already compressed)
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|avif)$ no-gzip
# Handle browser quirks
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# Add Vary header for proper caching
Header append Vary Accept-Encoding
</IfModule>Brotli 圧縮(mod_brotli)
# Brotli compression using mod_brotli (Apache 2.4.26+)
# Enable the module: a2enmod brotli
<IfModule mod_brotli.c>
# Compress text-based content types with Brotli
AddOutputFilterByType BROTLI_COMPRESS text/plain
AddOutputFilterByType BROTLI_COMPRESS text/html
AddOutputFilterByType BROTLI_COMPRESS text/xml
AddOutputFilterByType BROTLI_COMPRESS text/css
AddOutputFilterByType BROTLI_COMPRESS text/javascript
AddOutputFilterByType BROTLI_COMPRESS application/xml
AddOutputFilterByType BROTLI_COMPRESS application/xhtml+xml
AddOutputFilterByType BROTLI_COMPRESS application/javascript
AddOutputFilterByType BROTLI_COMPRESS application/json
AddOutputFilterByType BROTLI_COMPRESS application/ld+json
AddOutputFilterByType BROTLI_COMPRESS font/opentype
AddOutputFilterByType BROTLI_COMPRESS font/ttf
AddOutputFilterByType BROTLI_COMPRESS font/woff
AddOutputFilterByType BROTLI_COMPRESS font/woff2
AddOutputFilterByType BROTLI_COMPRESS image/svg+xml
# Brotli compression quality (0-11, default: 11)
# Lower = faster compression, larger files
# Higher = slower compression, smaller files
BrotliCompressionQuality 6
# Brotli window size (10-24, default: 22)
BrotliCompressionWindow 22
</IfModule>
# Fallback: Use Gzip if Brotli is not available
# Both modules can coexist; Apache serves Brotli to
# browsers that support it and Gzip to others.よくある間違いとその修正方法
.htaccess の問題のデバッグは困難な場合があります。開発者が最もよく犯す間違いとその回避方法をここに示します。
無限リダイレクトループ
最も一般的な間違いは、書き換え後の URL が同じルールに再度マッチするリダイレクトループの作成です。ルール適用前に RewriteCond で現在の状態をチェックし、マッチ後に [L] フラグで処理を停止してください。
# BAD: Creates an infinite loop
# (The rewritten URL "/new" matches "^(.*)$" again)
RewriteRule ^(.*)$ /new/$1 [R=301]
# GOOD: Use RewriteCond to prevent the loop
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/new/ [NC]
RewriteRule ^(.*)$ /new/$1 [R=301,L]
# GOOD: Another approach - check if already redirected
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)$ /new/$1 [R=301,L]間違った RewriteBase
RewriteBase はディレクトリ単位の書き換えの基本 URL パスを定義します。.htaccess がサブディレクトリにある場合、RewriteBase はそのパスと一致する必要があります。
# If .htaccess is in the document root:
RewriteEngine On
RewriteBase /
# If .htaccess is in /blog/ subdirectory:
RewriteEngine On
RewriteBase /blog/
# If .htaccess is in /app/public/ subdirectory:
RewriteEngine On
RewriteBase /app/public/
# Common mistake: Using RewriteBase /blog when file is at root
# This causes all rewritten URLs to be prefixed with /blogルールの順序が重要
Apache は .htaccess ルールを上から下に処理します。一般的なルールが特定のルールの前にあると、最初にマッチし、特定のルールは実行されません。特定のルールを一般的なルールの前に配置し、[L] フラグを使用してください。
# BAD: General rule before specific rule
RewriteEngine On
RewriteRule ^(.*)$ /index.php?page=$1 [L] # Catches everything!
RewriteRule ^about$ /about-us.html [R=301,L] # Never reached!
# GOOD: Specific rules first, general rules last
RewriteEngine On
RewriteRule ^about$ /about-us.html [R=301,L] # Specific: runs first
RewriteRule ^contact$ /contact-us.html [R=301,L] # Specific: runs second
RewriteCond %{REQUEST_FILENAME} !-f # Skip existing files
RewriteCond %{REQUEST_FILENAME} !-d # Skip existing dirs
RewriteRule ^(.*)$ /index.php?page=$1 [L] # General: fallback| 間違い | 修正方法 |
|---|---|
| RewriteEngine On の欠落 | 書き換えルールブロックの先頭に必ず "RewriteEngine On" を追加 |
| パターンでドットが未エスケープ | 正規表現パターンでは . の代わりに \. を使用(ドットは任意の文字にマッチ) |
| [L] フラグの忘れ | マッチ後にルール処理を停止するため [L] を追加 |
| Redirect と RewriteRule の混用 | 1つの方法に統一;混用は予期しない動作を引き起こす |
| ブラウザキャッシュをクリアせずにテスト | 301 リダイレクトはブラウザにキャッシュされる;テスト時は 302 を使用し、本番で 301 に変更 |
| .htaccess のファイルパーミッションが不正 | パーミッションを 644 に設定 |
よくある質問
.htaccess とは何ですか?どこに配置すべきですか?
.htaccess は Apache Web サーバーの分散設定ファイルです。Web サイトのルートディレクトリ(通常 public_html または www)に配置します。配置されたディレクトリとすべてのサブディレクトリに影響します。ファイル名は先頭のドットを含む ".htaccess" でなければなりません。
301 リダイレクトと 302 リダイレクトの違いは?
301 リダイレクトは永久的で、検索エンジンにリンク資産を新しい URL に移すよう指示します。302 リダイレクトは一時的で、検索エンジンは元の URL をインデックスに保持します。永久的な移動には 301、一時的な状況には 302 を使用します。ブラウザは 301 を積極的にキャッシュするため、テスト時は 302 を使用してください。
.htaccess のルールが機能しないのはなぜ?
最も一般的な原因:1)mod_rewrite が有効でない;2)AllowOverride が None に設定されている;3)ファイルパーミッションが不正(644 にすべき);4)構文エラー(Apache エラーログを確認);5)ブラウザが以前の 301 リダイレクトをキャッシュしている。
.htaccess は Nginx で使えますか?
いいえ、.htaccess は Apache 固有です。Nginx を使用する場合、同等のディレクティブを Nginx サーバーブロック設定に直接追加する必要があります。オンラインツールで .htaccess ルールを Nginx 設定に変換できますが、完全な一対一の変換ではありません。
サイトリニューアル後に旧 URL をリダイレクトするには?
旧 URL と新 URL のマッピングを作成し、それぞれに Redirect または RewriteRule を追加します。パターンベースの変更には正規表現キャプチャグループを使用します:RewriteRule ^blog/(.*)$ /articles/$1 [R=301,L]。必ず curl -I でリダイレクトをテストしてください。
.htaccess はサイトパフォーマンスにどう影響しますか?
Apache はリクエストごとに .htaccess を読み取るため、わずかなパフォーマンスオーバーヘッドがあります。高トラフィックサイトでは、ルールを Apache メイン設定に移動するのが望ましいです。ただし、ほとんどの Web サイトではパフォーマンスへの影響は無視できる程度です。
この .htaccess チートシートは、最も重要なリダイレクトパターン、セキュリティ設定、パフォーマンス最適化をカバーしています。本番環境にデプロイする前に、curl やオンラインリダイレクトチェッカーで変更を十分にテストし、動作する .htaccess ファイルのバックアップを保管してください。