.htaccess はウェブサイトへのアクセスを制御したり、様々な設定ができる。 Apache の httpd.conf でも設定できるが、httpd.conf に補足する形で使用できる。 ただし、Apache の httpd.conf にて .htaccess の使用が許可されてないと利用できない。 .htaccess は各ディレクトリに設置し、設置したディレクトリ以下でその設定が有効になる。 .htaccess を複数設置した場合、上位のディレクトリに設置したものから順に認識され、設定が反映される。 詳しくはApacheのサイト Apache チュートリアル: .htaccess ファイル に書かれている。 また、全ディレクティブを探す場合は Apache ディレクティブ一覧 が分かりやすい。
<Directory> はディレクトリ、<Location> はURLを指定できるディレクティブ(セクション)。
記述例としていろいろなブログ等に書かれているが、これらのディレクティブは基本的に httpd.conf で使用し、.htaccess では使えない。 VPS等root権限が使えるサーバーを除く多くのレンタルサーバーでは .htaccess しか編集できず、そこに <Directory> や <Location> を書いても Internal Server Error になるので注意する。
.htaccess でアクセスを制限する方法として従来はAllowやDenyが使われていたが、Apache 2.4系から Require が使われるようになった
レンタルサーバーでもApache 2.4系が導入され、Requireに書き換えなければいけないと思っている人もいるかもしれない。 実は Apache モジュール mod_access_compat が有効な場合、AllowやDenyも今までどおり使える。 私が使用しているさくらのレンタルサーバ、エックスサーバー、コアサーバーなどはApache 2.4系だが、AllowやDenyが使える。
AllowやDenyを使う場合、事前にOrder Allow,DenyのようにOrderを記述するのが基本だが、特定のIPアドレスやホスト名のアクセスを拒否するだけならdeny fromだけ書いても動作する。 それが正しいのかどうか分からないが、さくら、エックスサーバー、コアサーバーではそれで動作している。
特定のIPアドレスからのアクセスを拒否したい場合は以下のように書く。
Deny from 219.111.65.200
以下の場合は、210.108. で始まるIPアドレスがすべて対象となる。
Deny from 210.108.
幅広いIPアドレス帯域を設定するには、ネットマスク(CIDR)を利用して一括してIP帯域を指定できる。 この例は 210.108.0.0 ~ 210.108.255.255 までを指定したことになる。
Deny from 210.108.0.0/16
すべてのアクセスを拒否する場合は all と書く。
Deny from all
ホスト名(サブドメイン)も省略して制限できる。 この例では a.example.com や b.example.com など .example.com に一致するものがすべて対象となる。
Deny from .example.com
なお、サーバー変数(環境変数)REMOTE_HOSTに値がない場合でも、ここにドメインを記述することでサーバー側で逆引きが行われホスト名が取得できるようになる場合がある。 PHPだと$_SERVER['REMOTE_HOST']の値。 さくらはデフォルトで取得しており、エックスサーバー、コアサーバー(V1)、ConoHa WINGは記述することでホスト名が取得できるようになる。 コアサーバー(V2)では無効。
特定のIPアドレス(例では219.111.65.200)からのアクセスのみ許可したい場合は以下のように書く。
Allow from 219.111.65.200
以下のようにドメイン名でも制限できる。
Allow from adsl.example.com
Allow と Deny は優先順位を指定でき、先に書いた方が優先される。 以下の例だと Allow が先になる。
Order Allow,Deny
よく記述例で見かけるように一通り書くと以下のようになる。
Order Allow,Deny Allow from all Deny from 210.108.
Allow from all で全てのアクセスを許可した後、Deny from で拒否したいIPアドレスやホスト名を記述する。 この逆は以下のようになる。
Order Deny,Allow Deny from all Allow from 210.108.
Deny from all で全てのアクセスを拒否した後、Allow from で許可したいIPアドレスやホスト名を記述する。
<Limit> ディレクティブを使い、GETとPOSTの処理だけに適用することもできる。
<Limit GET POST> Order Deny,Allow Deny from all </Limit>
SetEnvIfは、環境変数を独自に定義できるディレクティブ。 環境変数はUser-Agent、Referer、Accept-Language、Remote_Host、Remote_Addr、Server_Addr、Request_Method、Request_Protocol、Request_URIなど。 以下は、User-Agent(ユーザーエージェント)にiPhoneやAndroidが含まれる場合、特定のURLへ飛ばすサンプル。
RewriteEngine On RewriteBase / SetEnvIf User-Agent "iPhone" UA=sp SetEnvIf User-Agent "Android" UA=sp RewriteCond %{REQUEST_URI} !^/sp.* RewriteCond %{ENV:UA} ^sp$ RewriteRule ^(.*)$ /sp/ [R,L]
また、Referer(参照元の情報)を取得して外部のサイトからのファイル(画像やページ)の参照を禁止することもできる。 詳しくは SetEnvIf Refererの設定 に書いた。
BrowserMatchは、上記 SetEnvIf User-Agent と同じ効果のディレクティブ。 BrowserMatchNoCaseは大文字・小文字を区別しない。 以下は、ユーザーエージェントに特定の文字列を含む場合、アクセスを拒否するサンプル。
BrowserMatchNoCase "Python-urllib" bad_bot BrowserMatchNoCase "Python/[0-9](.*)" bad_bot BrowserMatchNoCase "Go-http-client/[0-9](.*)" bad_bot BrowserMatchNoCase "claudebot" bad_bot Order Deny,Allow Deny from env=bad_bot
サイト運営で最もよくあるのは、一部のIPアドレスやホスト名のアクセスを拒否する方法で、例えば以下のように書く。
<RequireAll> Require all granted Require not ip 210.168. Require not host .kanagawa.ocn.ne.jp </RequireAll>
とりあえずディレクティブの動作を確認しようと <RequireAll> 内に何も書かないと Internal Server Error になる場合がある。
まず、Require all granted で全てのアクセスを許可する。 その後、Require not の後にアクセスを拒否したいIPアドレスやホスト名を書く。 それらはフルで書いても部分一致で書いても良い。
以下の例は上記の例と同じ効果がある。
<RequireAll> Require all granted <RequireNone> Require ip 210.168. Require host .kanagawa.ocn.ne.jp </RequireNone> </RequireAll>
<RequireNone> ディレクティブを使う場合は not を書かない。 拒否するIPアドレスやホスト名が多い場合は、この書き方が良いかもしれない。
また、Require の記述例として<Directory> や <Location> ディレクティブを併用した例もブログ等で見られるが、上述のように .htaccess しか使えないレンタルサーバーでは <Directory> や <Location> は使えず、エラーになるので注意する。 レンタルサーバーで使う場合は、基本的に <RequireAll> や <RequireNone> だけで記述する。
SetEnvIfを使って特定の環境変数のアクセスを拒否する場合は以下のように書く。
SetEnvIf Referer "example\.com" deny_ref <RequireAll> Require all granted Require not env deny_ref </RequireAll>
私はあまり使うことがないが、特定のIPアドレスやホスト名だけアクセスを許可する場合は以下のように書く。
<RequireAll> Require all denied Require ip 210.168. Require host .kanagawa.ocn.ne.jp </RequireAll>
Require all denied で全てのアクセスを拒否する。 その後、Require の後にアクセスを許可したいIPアドレスやホスト名を書く。
Redirect や RedirectMatch など .htaccess にてリダイレクトする方法はいろいろあるが、RewriteRule は柔軟に対応でき使いやすい。 RewriteRule はリダイレクトだけでなく、URLを書き換えたりいろいろできる。 話が長くなるので、RewriteRuleについては RewriteRule に書いた。
testディレクトリ以下のアクセスをsampleディレクトリにする場合、以下のように書く。
Redirect permanent /test/ http://www.example.com/sample/
testディレクトリ以下のディレクトリ構造を維持できるので、test/a.html、test/b.html があった場合、sample/a.html、sample/b.html にリダイレクトできる。 http://www.example.com/test/ から http://www.example.com/sample/ にリダイレクト(同じサイト内で別のディレクトリにリダイレクト)でも、http://www.example-test.net/test/ から http://www.example.com/sample/ にリダイレクト(別のサイトにリダイレクト)でもOK。
また、以下のようにリダイレクト先のURLに元のディレクトリ名の文字列(ここでは/test/)が含まれると永久ループしてエラーになる。
Redirect permanent /test/ http://www.example.com/sample/test/
以下の場合、testディレクトリ以下のアクセスをsample/test.htmlにリダイレクトできる。
Redirect permanent /test/ http://www.example.com/sample/test.html
以下のようなリダイレクトもできる。
Redirect permanent /test/abc.html http://www.example.com/sample/abc.php
正規表現を使ってリダイレクトできる。 以下の場合、URLの最後が.htmlでアクセスされたものを.htmlの部分だけ.phpに置き換えてアクセスさせる。 今までHTMLでページを作っていたものをPHPに変更して、ファイル名はそのまま(拡張子だけ変更)というような場合などに使う。
RedirectMatch (.*)\.html$ http://www.example.com$1.php
以下の場合、windows_という文字を含み、URLの最後が.phpなURLを http://www.example.com/internet/pc/ にリダイレクトする。
RedirectMatch (.*)windows_(.*)\.php$ http://www.example.com/internet/pc/
以下の場合、websiteという文字を含むURLを http://www.example.com/memo/website/ にリダイレクトする。
RedirectMatch (.*)website/(.*)$ http://www.example.com/memo/website/$2
例えば「http://www.example.com/internet/website/任意のファイル名」を「http://www.example.com/memo/website/任意のファイル名」にリダイレクトしたい場合、このRedirectMatchを http://www.example.com/internet/ 以下に置く。 ディレクトリを変更した場合などに利用できる。
特定のファイルにのみ設定を行う場合は<Files>ディレクティブを使う。 Filesの後にファイル名を書く。
<Files example.cgi> AddType text/html .cgi </Files>
特定の拡張子を持つなど、一定のルールがあるファイル名を複数指定したい場合は正規表現が便利。 該当ファイルに一致する文字列を正規表現で書く。
<Files ~ "\.cgi$"> AddType text/html .cgi </Files>
正規表現を使う場合、FilesMatchという選択肢もある。 ~ を書く必要がない。
<FilesMatch "\.cgi$"> AddType text/html .cgi </FilesMatch>
初期設定にないMIMEタイプ(Content-Type、ファイルの種類)を追加する場合はAddTypeを使う。
AddType text/html .cgi #AddType application/x-httpd-cgi .cgi AddType application/x-httpd-php .php AddType application/xml .rdf
ファイルの種類によってはMIMEタイプを設定しないと正常にダウンロードできなかったり、ブラウザで認識されない場合がある。 なお、PHPなどのプログラムで出力する場合、ヘッダー情報にContent-Typeを記述すれば、基本的にAddTypeは必要はない。
拡張子を省略したり、複数まとめて記述することもできる。
AddType image/jpeg jpeg jpg AddType text/html .cgi .pl .rb .py
拡張子を指定せずにMIMEタイプを設定できる。 特に指定がないと該当ディレクトリの全てのファイルに適用される。 デフォルトのMIMEタイプは上書きされる。
ForceType text/html
Noneで無効にできる
ForceType None
特定のファイルにのみ適用するには<Files>ディレクティブなどを使う。
<Files example.cgi> ForceType text/html </Files>
<FilesMatch "\.(cgi|pl)$"> ForceType text/html </FilesMatch>
拡張子があるファイルはAddTypeを使えばよいが、拡張子がないファイルを扱わなければいけない場合もある。 例えば、exampleというファイルにtext/htmlというMIMEタイプを指定する場合は以下のように記述する。
<Files example> ForceType text/html </Files>
MIMEタイプが分からないが、とりあえず初期値を設定したい場合などに使用する。 ForceTypeと同様、特に指定がないと該当ディレクトリの全てのファイルに適用される。
DefaultType text/html
何も指定しない場合はNoneを書く。
DefaultType None
CGI関連のディレクティブは、昨今レンタルサーバーにてデフォルトで設定されているものが多く、あまり使わなくなったが、一応記述例を書いておく。
以下の例はCGIの実行を許可し、Indexファイル(index.htmlなど)がない場合にディレクトリ構造を表示しないようになる。 CGIが使えるレンタルサーバーでは最初からこの設定が行われているので基本的に記述する必要はない。
Options +ExecCGI -Indexes
Options は + でその設定を追加、- で削除になる。 + や - が付いたものと付けないものを混在させるのはApacheのドキュメントによると正しくないらしい。 Options には以下の種類がある。
詳しくはApacheのサイト Options ディレクティブ に書かれている。
CGIが最初から利用できるサーバーでは特に設定は必要ないが、.htaccessで指定しないと動作しない場合は以下のように記述する。
Options +ExecCGI AddHandler cgi-script .cgi .pl
上の例では拡張子が .cgi と .pl のファイルがCGIアプリケーションとして動作するようになる。 拡張子はスペースで区切って複数指定できる。 以下はSSIの場合(拡張子shtmlというファイルでSSIを利用する場合)。
Options +Includes AddType text/html .shtml AddHandler server-parsed .shtml AddOutputFilter INCLUDES .shtml
レンタルサーバーの設定によるが、Perl、Ruby、Pythonで書いたCGIプログラムを動かすには、拡張子を .cgi にして中身をそれぞれの言語で書き、パーミッションを設定すれば良い。 パーミッションは 755 とは限らず、レンタルサーバーによって異なる場合がある。 拡張子が .cgi では面白くないという人は、.pl、.rb、.pyでCGIプログラムが動くように以下のように設定する。
AddHandler cgi-script .pl .rb .py
http://www.example.com/test/ のようにディレクトリ名だけを指定してアクセスすると index.html や index.cgi などが表示される。 もとは httpd.conf に記載されているが、この最初に表示されるページの優先順位を変更するには DirectoryIndex を使う。
DirectoryIndex index.php index.html index.cgi top.html
先頭に書いたものほど優先され、該当のファイルがなければ順次後ろのファイルを探して表示する。 また、DirectoryIndexが指定されていない場合や、DirectoryIndexで指定したファイルがすべてなかった場合、ディレクトリ構造の一覧が見えてしまう場合がある。 それを防ぐには以下のように .ht を記述する。
DirectoryIndex index.php index.html index.htm index.cgi .ht
ページが見つからなかったり、サーバーエラーが発生した場合など、何らかのエラーが発生した場合に表示するページを指定できる。 以下のようにHTTPステータスコードを指定して記述する。
ErrorDocument 403 /data/html/403.html ErrorDocument 404 /data/html/404.html ErrorDocument 500 /data/html/500.html
また、URL(ドメイン)を指定して自サイトまたは他サイトへ飛ばすこともできる。
ErrorDocument 403 http://www.example.com/data/html/403.html
ページにアクセスした際、パスで書いた場合はエラーページに転送されてURLは元のページのまま、URLを書いた場合はエラーページに転送されURLも転送先のものに変わる。
Basic認証はユーザ名とパスワードを入力するウィンドウを表示させて、ページにアクセスできる人を制限できる。 .htaccessと.htpasswdの2つのファイルが必要で、まず.htaccessに以下のように書く。
AuthUserFile /htdocs/sample/.htpasswd AuthName "Secret Area" AuthType Basic require valid-user <Files ~ "^\.ht"> deny from all </Files>
AuthUserFileには.htpasswdを置いたディレクトリのパスを書く。 次に.htpasswdに以下のように書く。
sample:ABwOg1D2JDxIQ
これはユーザ名:sample、パスワード:test の場合の例。 .htpasswdには「ユーザ名:cryptしたパスワード」という書式で書く。 ABwOg1D2JDxIQ は test を AB という種(salt)をもとに crypt した結果の文字列。
以下はサイトのメンテナンスを行う場合のサンプル。 ディレクトリをリネームする場合、http://www.example.com/abc/ を http://www.example.com/abc2/ などにしておき、トップの.htaccessでエラーページを指定する。
ErrorDocument 403 /info/maintenance/index.html ErrorDocument 404 /info/maintenance/index.html ErrorDocument 500 /info/maintenance/index.html
リダイレクトする(リネームしたくない)場合、http://www.example.com/abc/ の.htaccessに以下のように書く。
Redirect permanent /abc/ http://www.example.com/info/maintenance/
以下のようにパスに同じ文字列(例ではabc)を含むとループになるので注意。
Redirect permanent /abc/ http://www.example.com/info/abc/
Redirectはディレクトリの階層構造がそのまま反映され http://www.example.com/info/maintenance/ 以下全てのアクセスがエラーになるので、http://www.example.com/info/maintenance/ の.htaccessに 以下を書く。
ErrorDocument 403 /info/maintenance/index.html ErrorDocument 404 /info/maintenance/index.html ErrorDocument 500 /info/maintenance/index.html