私です。お母様と「httpからhttpsにリダイレクトさせたいのにどうするんだっけ?」を繰り返している皆々様、お元気ですか。
表題の件ですが、検索するとRewrite
よるURL書き換えばかりです。令和になってもこの調子で良いのか疑問に思ったので自分で調べることにしました。
忘れちゃイケナイHSTS
HTTP Strict Transport Security、通称HSTS。
ブラウザに「このサイトはhttps
が実装してあるよ」と教えてあげるhttpヘッダー。強制力と信頼性は無いのでおまけのようなもの。
詳しいことはMDNの方で。
形式は次の通り。
Strict-Transport-Security: max-age=31536000
必須ディレクティブであるmax-age
ではキャッシュ期間を指定する。31536000
あれば良いかもしれない。
キャッシュ期間中はブラウザが自主的にリダイレクトを行う。
なぜ max-age=31536000
なのか?
※これは私の解釈です。
ドメイン、あるいはSSL/TLS証明書やサーバーの更新はほぼ年単位で行われ、HSTSのキャッシュ期間も31536000 = 60 * 60 * 24 * 365
、つまり1年(年単位)にして間違いないだろう。
どうせブラウザ側の都合でキャッシュクリアされる可能性がある上、キャッシュ期間をこれより短くして得られるメリットがあるのかよく考えてほしい。
実装
主要なApache、nginx、LSWSに限定する。LSWSは都合上「OpenLiteSpeed」の事を指す。
前提としてLet’s EncryptによるHTTP-01チャレンジ検証1で失敗しないよう、http://<YOUR_DOMAIN>/.well-known/acme-challenge/
にアクセスしても強制リダイレクトが発生しない仕組みで実装する。
Apache 2.4+
Apache 2.4のコアモジュールには<If>
が追加実装されている。mod_aliasと組み合わせることにより、シンプルに記述できる。
Header onsuccess set Strict-Transport-Security "max-age=31536000"
<If "%{HTTPS} != 'on' && %{REQUEST_URI} !~ m#^/\.well-known/acme-challenge/.*#">
# <If "%{HTTPS} != 'on'">
Redirect permanent "https://%{HTTP_HOST}%{REQUEST_URI}"
</If>
HTTPステータスが200ならHSTSヘッダーを上書き追加する。
HTTP-01チャレンジを使用してないならコメントアウトしている<If ...
と差し替える。
【必須モジュール】mod_headers + mod_aliasが必要。どちらか欠けても500 Internal Server Error
を返す。
Apache 2.x
mod_rewriteを使った古典的なリダイレクト方式。
Header onsuccess set Strict-Transport-Security "max-age=31536000"
RewriteEngine on
RewriteCond %{HTTPS} "!='on'"
RewriteCond %{REQUEST_URI} "!^/\.well-known/acme-challenge/.*"
RewriteRule .* "https://%{HTTP_HOST}/$0" [R=301]
上記で説明してるので端折るが、HTTP-01チャレンジ検証を利用してないなら4行目は削除して良い。
【必須モジュール】mod_headers + mod_rewriteが必要。どちらか欠けても500 Internal Server Error
を返す。
nginx
return
による単純なリダイレクトで処理する。
location ~ "^/(?!\.well-known/acme-challenge/)" {
# location / {
add_header Strict-Transport-Security "max-age=31536000";
if ($https != “on”) {
return 301 "https://$http_host$request_uri";
}
}
【必須モジュール】ngx_http_headers_module + ngx_http_rewrite_module
LiteSpeed Web Server
LSWSはApacheのRewrite
の設定内容をほぼそのまま使える。RewriteRule
のパターンには、パッチ先頭に/
を含むようで、一応修正する2。
Rewrite
の内容のみ.htaccess
も利用可。どちらの方法でもリロード(再起動)は必要。
LiteSpeed WebAdmin コンソールから → バーチャルホスト → 対象ホストを編集 → コンテキスト より
-
URI:
/
(重複不可) -
アクセス可能:
はい
Strict-Transport-Security: max-age=31536000
-
Rewriteを有効にする:
はい
RewriteCond %{HTTPS} "!='on'"
RewriteCond %{REQUEST_URI} "!^/\.well-known/acme-challenge/.*"
RewriteRule ^/?(.*)$ "https://%{HTTP_HOST}/$1" [R=301]
あとはリロードを実行することで適用される。
一応設定ファイルの一部内容を置いておきます。可能ならウェブコンソールから設定を行って欲しい。
設定ファイルのサンプル内容
context / {
allowBrowse 1
extraHeaders <<<END_extraHeaders
Strict-Transport-Security: max-age=31536000
END_extraHeaders
rewrite {
enable 1
RewriteCond %{HTTPS} "!='on'"
RewriteCond %{REQUEST_URI} "!^/\.well-known/acme-challenge/.*"
RewriteRule ^/?(.*)$ "https://%{HTTP_HOST}/$1" [R=301]
}
}
後記
本来Rewrite
系はURLの置換によるリダイレクトである。当時は条件式系のディレクティブが発達しておらず仕方なくRewrite
を使う感じになっているがあまりにも定着しすぎている。Apache 2.4から<If>
<ElseIf>
<Else>
ディレクティブの登場で単体で使う場面があまり少ないであろうRedirect
も日の目を見ることができそうだ。
Apache 2.4は初版から10年経過しているので、置き換えの必要ないならシンプルなリダイレクトにするべき。
あとnginxのif
がApacheほど使えない3ので最終的にlocation
に頼りがちになる。個人的に比較演算子の考え方はApacheの方が好みで、正規表現で扱う文字数はなるべく減らしたいので不一致があるのはとても助かる。
-
コアでは無く、
ngx_http_rewrite_module
に実装されてるおまけのような機能。公式Wikiでも酷評されがち → If is Evil… when used in location context ↩