【Nginx】wwwありとなしを統一する

ドメインが example.comwww.example.com の2つがあり、これらを統一するときのベストプラクティスです

方法としてはnginx.confにリダイレクトのルールを書きますが、その書き方について公式から言及されていました

https://mogile.web.fc2.com/nginx_wiki/start/topics/tutorials/config_pitfalls/#server-name-if


まず、nginxのconfig内ではifを使ってはいけないそうです。禁止というわけではありませんが、極力使うなと書いてあります。

ifは邪悪

複数のserver_nameを指定する

example.comwww.example.comが存在するときに、どちらにアクセスしてもexample.comが表示されるようにしたいとします。

その場合server_nameを2つ書くわけですが、見た目をスッキリさせる目的等で以下のように書いてしまうことがあります。

server {
    server_name example.com *.example.com;
        if ($host ~* ^www\.(.+)) {
            set $raw_domain $1;
            rewrite ^/(.*)$ $raw_domain/$1 permanent;
        }
        # [...]
    }
}

これはserver_nameを2つ指定して$hostで判定してリダイレクトするというものです。
しかしこれは先程のifは邪悪で言われたifを使ってしまっています。

なぜだめなのかというと、その理由も書いてあります。

これには実際のところ3つの問題があります。1つ目はif です。私達が今心配しているのはそれです。なぜこれが悪いのか?Ifは邪悪 を読みましたか?NGINXがリクエストを受信すると – 要求されたサブドメインが何であっても、それが www.example.com あるいは単なる example.com であっても – こif ディレクティブは常に評価されます。全てのリクエストについてHostヘッダをチェックするようにNGINXに夜言う窮しているため、非常に非効率です。それはさけなければなりません。代わりに、以下の例のように2つのserverディレクティブを使います。

3つといいつつ1つしか教えてくれませんでしたが、つまり 全てのリクエストに対して毎回ifで処理が入ってしまうから、やめたほうがいいよ という感じでしょうか


良い書き方は以下です

server {
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}
server {
    server_name example.com;
    # [...]
}

上記のようにすることで、server_nameごとになにが処理されるかわかりやすいです。
$schemeが使われていますが、これはhttpとhttpsをハードコートしないようにするために書かれているそうです。

意図的にhttpsにアクセスさせたい場合はreturn 301 https://example.com$request_uriとしても良いと思います(個人の意見)

リダイレクトの方法

リダイレクトの方法で正規表現を使う方法がよくあります
rewriteです。

しかしこれは公式ではあまり使わないほうが良いとされています。

理由は 正規表現で混乱するから だそうです

悪い:
rewrite ^/(.*)$ http://example.com/$1 permanent;

良い:
rewrite ^ http://example.com$request_uri? permanent;

より良い:
return 301 http://example.com$request_uri;

上を見てください。そしてここに戻ってください。そして上に行き、ここに戻ってください。OK. 最初のrewriteは完全なURIから最初のスラッシュを引いたものをキャプチャします。組み込み変数 $request_uri を使うことで、キャプチャやマッチングを多少なりとも効果的に回避できます。

正規表現を使ってややこしくするより、returnを書いたほうがわかりやすいということですね