.htaccessは、Apache HTTP Serverの設定をdirectory単位で追加・上書きするための分散設定fileです。shared hostingのようにhttpd.confを編集できない環境で、redirect、URL rewrite、directory index、access制御などを設定できます。
ただし、main server configを編集できる場合、Apache公式は同じdirectiveを<Directory>へ書く方法を推奨しています。.htaccessはrequestごとに探索・読み込みされ、利用者へserver設定を変更する権限も渡すためです。
最初に要点を整理します。
- .htaccessは配置したdirectoryと、その配下のrequestへ適用される
- 利用可否はhttpd.conf側の
AllowOverride・AllowOverrideListで決まる AllowOverride Allは必須ではなく、必要な権限だけ許可する- 変更は次のrequestから読まれるため、通常Apacheのreloadは不要
- syntax errorや許可されないdirectiveはHTTP 500の原因になる
この記事ではApache 2.4を前提に、作成方法、権限設定、基本例、RewriteRule、error診断まで解説します。
.htaccessとは
.htaccessは「distributed configuration file」と呼ばれます。通常のfile名は.htaccessですが、server管理者はAccessFileNameで変更できます。
# main server configでfile名を変更する例
AccessFileName ".config"
一般的な環境ではfile名を変えず、DocumentRootまたは設定したいsubdirectoryへ配置します。
/var/www/example/public/
├── .htaccess
├── index.php
├── assets/
└── admin/
└── .htaccess
rootの.htaccessはpublic directory以下へ影響します。admin directoryにも.htaccessがあれば、両方のconfigがdirectiveごとのmerge ruleに従って評価されます。
.htaccessを使うべき場面
次のようにmain server configを編集できない場合が主な用途です。
- shared hostingでhttpd.confやVirtualHostへaccessできない
- directory単位の設定をsite運営者へ委任する必要がある
- WordPressなどapplicationがrewrite ruleを管理する運用になっている
server・containerを自分で管理できるなら、同じ設定をVirtualHost内のDirectory sectionへ置くほうが明確です。
<Directory "/var/www/example/public">
Options -Indexes
DirectoryIndex index.php index.html
</Directory>
server側の設定場所、VirtualHost、Directoryの作り方はApache httpd.confの場所と設定方法で解説しています。
AllowOverrideで.htaccessを有効にする
.htaccessを置くだけでは、すべてのdirectiveが使えるわけではありません。server管理者がhttpd.conf、apache2.conf、VirtualHostなどのDirectory sectionで許可します。
<Directory "/var/www/example/public">
AllowOverride FileInfo Indexes
Require all granted
</Directory>
この例はFileInfoとIndexes classのdirectiveを.htaccessで使えるようにします。Require all grantedはApache 2.4のauthorizationです。
AllowOverrideは.htaccess自身に書けない
次の設定を.htaccessへ追加しても、自分自身の権限を広げることはできません。
# .htaccessへ書いて有効化することはできない
AllowOverride All
AllowOverrideはserver config・VirtualHost・Directory contextで管理者が設定します。shared hostingではhosting providerが定めた許可範囲を確認します。
AllowOverride Allは必須ではない
すべてのclassを許可する必要はありません。必要な用途に絞ります。
| class | 主な用途 | directive例 |
|---|---|---|
AuthConfig |
authentication | AuthType、AuthUserFile |
FileInfo |
URL mapping・header・content type | RewriteRule、Redirect、Header |
Indexes |
directory index | DirectoryIndex |
Limit |
host・request access制御 | Require |
Options |
directory feature | Options |
各directiveのApache公式docsにはContextとOverrideが記載されています。.htaccessがContextに含まれ、serverのAllowOverrideに必要なclassがあるか確認します。詳しい読み方はApacheのcontextとdirectiveを参照してください。
AllowOverrideListでdirective単位に許可する
Apache 2.4では、AllowOverrideListで許可するdirective名を個別指定できます。
<Directory "/var/www/example/public">
AllowOverride None
AllowOverrideList RewriteEngine RewriteCond RewriteRule
Require all granted
</Directory>
この例ではrewriteに必要な3directiveだけを許可します。指定されていないdirectiveを.htaccessへ書くとserver errorになります。
category単位のAllowOverrideより細かく制限できるため、applicationが必要とするdirectiveを把握できる環境では有効です。
.htaccessファイルを作成する
file名は先頭がdotの.htaccessです。macOS・Linuxやfile managerではhidden fileとして表示されない場合があります。
作成時は次を確認します。
.htaccess.txtになっていない- plain textで保存している
- Apache processがfileとparent directoryを読み取れる
- Web application processから不用意に書き換えられないpermissionにする
- 変更前のfileをbackupしてすぐ戻せる
最小の動作確認にはcommentだけでも構いません。
# Site-specific Apache settings
コメントと基本構文
#から行末まではcommentです。directive名とargumentを空白で区切ります。
# index.phpを先に探し、なければindex.htmlを探す
DirectoryIndex index.php index.html
# directory listingを無効化する
Options -Indexes
pathなどに空白がある場合はquoteします。main configと基本構文は同じですが、すべてのdirectiveを.htaccessへ書けるわけではありません。
DirectoryIndexを設定する
directory URLへaccessしたときに探すfileを指定します。
DirectoryIndex index.php index.html
https://example.com/docs/へのrequestなら、docs directory内のindex.php、次にindex.htmlを探します。
DirectoryIndexを.htaccessで使うには、通常AllowOverrideのIndexes classまたはAllowOverrideListでの明示許可が必要です。
Options -Indexesでfile一覧を防ぐ
DirectoryIndexに該当するfileがなく、Indexesが有効だとdirectory内のfile一覧が表示される場合があります。
Options -Indexes
-は既存OptionsからIndexesだけを無効化する意味です。Options Allのように不要なfeatureまで広く有効化せず、差分を明示します。
Options directiveにはAllowOverride OptionsまたはAllowOverrideListの許可が必要です。許可されていない環境で書くと500 errorになります。
Requireでaccessを制御する
Apache 2.4ではRequireでauthorizationを設定します。
# すべてのrequestを拒否
Require all denied
特定IP addressだけ許可する例です。
Require ip 192.0.2.10 198.51.100.0/24
複数条件を組み合わせる場合はRequireAll・RequireAnyなどのauthorization containerを使います。古いApache 2.2向けのOrder、Allow from、Deny fromとApache 2.4のRequireを安易に混在させません。
Requireを.htaccessで使うにはLimitまたはAuthConfigなど、使うproviderに対応したoverride権限を確認します。hosting環境のaccess制御機能が別にある場合は、その運用との競合も確認してください。
Redirectで単純な転送を設定する
単純な旧URLから新URLへの転送はmod_aliasのRedirectで書けます。
Redirect 302 "/old-page" "/new-page"
最初は302 temporary redirectでLocationと転送先を確認し、恒久移転だと確定してから301へ変更します。
Redirect 301 "/old-page" "/new-page"
browserやsearch engineは301を長くcacheすることがあります。誤った301は修正後も古い転送が見えるため、private windowやcurl -Iでも確認します。
複数条件・query string・file存在判定が必要ならRewriteRuleを使います。redirect loopを含む詳しい設計は.htaccessでredirectする方法で分離して解説しています。
RewriteRuleでfront controllerへ送る
存在しないfile・directoryへのrequestをindex.phpへ送る基本例です。
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [END]
!-f: 実在fileでない場合!-d: 実在directoryでない場合RewriteRule ^: 残りのURL pathへmatch[END]: 現在のper-directory rewrite処理を終了
mod_rewriteがloadされ、AllowOverride FileInfoまたは必要なAllowOverrideListが設定されている必要があります。
.htaccessのpatternは先頭slashなし
.htaccessのRewriteRuleは、配置directoryのprefixを除いたpathへmatchします。patternを^/productsで始めるとmatchしません。
# /shop/.htaccess で /shop/products/42 にmatch
RewriteRule "^products/([0-9]+)$" "product.php?id=$1" [END,QSA]
この例でRewriteRuleが見るのはproducts/42です。/shop/も先頭slashも含みません。
RewriteRuleのpattern・substitution・flagはApache RewriteRuleの基本で詳しく扱っています。
RewriteBaseが必要な場合
多くの一般的な構成ではRewriteBaseを明示する必要はありません。AliasやsymlinkでURL pathとfilesystem pathが異なる、subdirectory applicationでrelative substitutionが意図しない場所へ解決される場合に確認します。
RewriteEngine On
RewriteBase "/shop/"
RewriteRule "^products$" "index.php?page=products" [END,QSA]
意味を確認せずにすべてのsampleへRewriteBaseを追加しないようにします。
上位・下位.htaccessの適用を理解する
上位directoryと下位directoryの.htaccessが両方存在する場合、「下位が必ず上位をすべて上書きする」とは限りません。directiveごとにmerge方法が異なります。
特にmod_rewriteのrule inheritanceには独自の扱いがあり、subdirectoryに別の.htaccessがあるとparentのrule setが想定どおり継承されない場合があります。必要ならRewriteOptionsのInherit系設定を公式docsで確認します。
まずは.htaccessを不用意に階層ごとへ増やさず、site rootへ集約できるか検討します。複数fileが必要なら、各fileの責務と適用directoryを記録します。
.htaccess変更にApache再起動は必要か
.htaccessはrequest時に探索・読み込みされるため、通常はApacheのrestart・reloadなしで次のrequestから反映されます。
これは同時に、間違った設定もすぐrequestへ影響するという意味です。syntax errorや許可されないdirectiveがあると、そのdirectoryへのrequestが500になることがあります。
main server config側でAllowOverrideやmoduleを変更した場合は、server configの構文checkとreloadが必要です。
.htaccessが反映されないときの確認方法
次の順番で切り分けます。
- file名が正確に
.htaccessか確認する - requestされるfilesystem directoryと配置場所が一致するか確認する
- 親Directory sectionのAllowOverride・AllowOverrideListを確認する
- directiveの公式docsでContextとOverrideを確認する
- 必要なmoduleがloadされているか確認する
- file・directory permissionを確認する
- Apache error logを確認する
- redirectはbrowser cacheを避けてstatusとLocationを確認する
500 Internal Server Error
最初に直前の変更を戻し、siteを復旧します。その後error logでfile・line・messageを確認します。
代表的な原因です。
- directive名やargumentの誤り
- そのdirectiveが.htaccess contextで使えない
- AllowOverrideで必要なclassが許可されていない
- moduleがloadされていない
- quoteやregular expressionのsyntax error
Options not allowed here
Options overrideが許可されていない可能性があります。shared hostingでは勝手にAllowOverrideを変更できないため、providerの仕様を確認します。server管理者ならAllowOverride Optionsではなく、必要に応じてAllowOverrideListでOptionsだけを許可する方法も検討します。
RewriteRuleが動かない
RewriteEngine On、mod_rewrite、FileInfo権限、patternの先頭slash、配置directory、実在file / directoryのRewriteCondを確認します。
debug時はserver config側で一時的にrewrite log levelを上げられますが、productionでtrace levelを長時間有効にすると大量のlogとperformance低下につながります。
403 Forbidden
Requireによるdeny、filesystem permission、Directory側のaccess設定、Options、symlink policyを確認します。.htaccessだけでなく、main configとVirtualHostを含むmerge結果で判断します。
安全に編集する手順
- 現在の.htaccessを別名でbackupする
- 一度に1目的だけ変更する
- redirectは302でtestする
- 正常URL・存在しないURL・管理画面・static fileを確認する
- HTTP status、Location、response bodyを確認する
- error logに新しいwarning・errorがないか確認する
- 恒久移転を確認してから301へ変更する
command lineでheaderだけを確認できます。
curl -I https://example.com/old-page
WordPressやframeworkが.htaccessの一部を自動生成する場合は、管理範囲を示すcommentの内側を手作業で変更しないようにします。次回の設定保存で上書きされる可能性があります。
.htaccessのperformanceとsecurity
AllowOverrideが有効なdirectoryでは、Apacheはrequestされたfileまでのpathで.htaccessを探索します。fileが存在しなくても探索costが発生し、存在すればrequestごとに読み込み・parseされます。
また、.htaccessを編集できるuserへ、許可したdirectiveの範囲でserver behaviorを変える権限を渡します。
対策は次のとおりです。
- main configを編集できるならDirectory sectionへ移す
- 不要なdirectoryはAllowOverride Noneにする
- Allではなく必要なoverride classだけ許可する
- 可能ならAllowOverrideListでdirective名を限定する
- .htaccessをapplicationから不用意に書き込み可能にしない
- DocumentRootには公開してよいfileだけを置く
.htaccess運用チェックリスト
- main server configへ書けない理由がある
- 配置directoryと影響範囲を把握した
- AllowOverride Allを無条件に使っていない
- directiveのContextとOverrideを公式docsで確認した
- AllowOverrideListで絞れるか検討した
- Apache 2.4のRequireを使い、2.2記法を混在させていない
- RewriteRule patternを先頭slashで始めていない
- redirectは302で確認してから301へ変更した
- backupと即時rollback手順がある
- HTTP status・Location・error logを確認した
まとめ
.htaccessはdirectory単位でApache設定を変更できる便利なfileですが、使えるdirectiveはserver側のAllowOverride・AllowOverrideListで決まります。AllowOverride Allは必須ではなく、FileInfo、Indexes、Optionsなど必要なclass、またはdirective名だけを許可します。
基本的なDirectoryIndex、Options、Require、Redirect、RewriteRuleを目的別に使い、per-directory rewriteではpatternの先頭slashとdirectory prefixが除かれる点に注意します。
main server configを編集できる場合はDirectory sectionを優先し、.htaccessが必要な環境ではbackup、最小権限、302 test、HTTP・error log確認を一連の手順にしてください。