NGINXで「www」の有無とhttpのhttpsの正規化をする話

久しぶりにありふれたネタのような、そうでもないようなそんな話を書きたいと思います。この話をわざわざ書こうと思った理由は後程紹介します。

今回は、タイトルの通りURLの正規化のお話です。なぜこのようなことを行うのかというと、SEOの評価的な観点や、設定を誤ると、特定のURLではサイトにアクセスできなくなりアクセス数が減ることが予想されるためです。このサイトは基本的にSEOは殆ど意識していないサイトではありますが、高速化や最低限の評価はしてもらえるように工夫はしており、このサイトの運営資金はこのサイトから生み出すために最低限の工夫ぐらいはしているわけです。

そういった意味では、URLの正規化というのは必須かというとそういうわけでもありませんし、wwwの有り無しでそもそもサイトを分けるという方もいるでしょう。ですが、私はそういったことを考えていないので正規化を行います。

この手の話はありふれているのになぜ行うのかというと、書かれている方法が使えないからですね。後はシンプルに疑問だったことがあり、多くの方がそれについて(わかりきっているのか)無視しているので、その点を解説しようと思います。後は、自分の不手際でウェブサーバーを一から作り直す羽目になったので、そのための備忘録的な側面もあります。

というわけで、説明していきます。

目次

URLの正規化パターン

URLのパターンはwwwの有無とhttpsかhttpかの違いに分けられます。

この中でhttpsかhttpについては、基本的にhttpの場合はhttpsへ、httpsのままはそのままにするのが望ましい状態です。

一方でwwwの有無というのは、そもそもwwwの有無で別サイトである可能性もあるので、どちらかにするのは最初の環境構築の時点で決まると言えます。www無で想定してサイトを構築している場合はwww無で正規化するべきですし、wwwありならそのように正規化する必要があります。ここでは、wwwありに統一する前提で話します。ただし、この前提は後の話で効いてくる部分なので、もし初期環境の構築ならばwww無の環境の方が構築が楽になる可能性があります。詳しくは次の章で説明します。

アクセスパターンとしては、それぞれ2つのパターンがあるので、4通りあることになりますので、残る3つのパターンは全て同一の形式にリダイレクトされる必要があります。

また、一般的にリダイレクトには301と302の2種類のステータスが存在しますが、SEO的観点ではどちらでも影響はないと明言されています。

-Youtube- Google Search Centralチャンネル
https://youtu.be/87NIFnSAvDw?si=dEe0j9y8Jq9JpRM1

機能的には変わらないものの、ステータスとしては明確に違うコードの違いですが、上記動画によるとこの二つのリダイレクト方式は「違いはわずかだが小さい(the difference is subtle but small.)」という書き方をされています。

ということで、基本的にはどちらでも良いが、正しく使い分けて欲しいということを動画内では言っているので、URLの正規化には301(恒久的なリダイレクトを表す)のステータスを設定するのが妥当です。

CNAMEコードとSSL

今回はwwwありに統一する話で書きましたが、よく考えるべきことが潜在的に存在することがわかります。それはSSLの証明書についてです。

証明書が不要な通常のhttpの通信では、httpsへリダイレクトしても、wwwの有無も問題なく簡単にリダイレクトが可能です。

一方でhttpsのリンクにするためのSSL通信を行うには証明書が必要です。この中身にはどのサイトかを示すことが証明されているわけですが、wwwの有無は気にしないで良いのでしょうか。

答えはNOで、気にする必要があります。これは先ほども書いたように別サイトである可能性もあるので、別の証明書でなければ正しく認証できないはずです。また、正しく認証しようとすると、二つの証明書が必要になりコストが2倍になってしまいます。個人のサイトの方で無料の証明書を使うならまだしも、企業の方などで有料の証明書の場合は考え物かもしれません。

ですが、このことについて触れているサイトは殆ど見かけることができませんでした。なぜでしょうか。

それはCNAMEレコードを設定することに関係しています。ドメインの登録に直接的に関係するものは、Aレコード、AAAAレコード、CNAMEレコードの3種類があります。AレコードはIPv4で使うIPアドレスの対応を示し、AAAAレコードはIPv6でのIPアドレスを紐づけるレコードです。

それに対してCNAMEレコードは、ドメインを紐づける機能(正規ホスト名に対する別名を定義するレコード)で、このサイトを例にとると、「thun-techblog.com」のCNAMEレコードに「www.thun-techblog.com」を登録すると、「thun-techblog.com」は「www.thun-techblog.com」として別名として登録されます。

イメージとしては「thun-techblog.com」は「www.thun-techblog」でもあり、「www.thun-techblog.com」のIPを参照します。

ですので、CNAMEレコードをwww有無で正規化したい方に合わせて登録しておくと、SSL接続の証明書の名前が食い違うことはなくリダイレクトできるのです。

便利ですが、これが今回の記事を書こうと思った原因でもあります。

お名前ドットコムで契約しているドメインなのですが、CNAMEレコードについてのヘルプはこのページに掲載されています。ここで、前提条件が効いてくるのですが、今回はwww有へのリダイレクトです。つまり、「thun-techblog.com」にCNAMEレコードを設定する必要があります。しかし、ヘルプページによると、

※ホスト名なしのCNAMEレコードは登録することができません。

https://help.onamae.com/answer/7883

ということで、ドメインにお名前ドットコムを使っていてかつ、このwww有の正規化の方法だと、httpsのリンクは迂闊にリダイレクトできないということになります。

他のドメイン会社なら違うのかというと違うと思います。しかし、利便性的な観点でおすすめできないです。というのも、CNAMEレコードを設定した際、他のレコードは一切設定してはいけない決まりがあります(RFC1912)。なので、CNAMEレコードを設定した時点でメールの送受信のMXレコードやTXTレコードが使えなくなるので、ホスト名がない状態でのCNAMEレコードの登録はおすすめできません。

なので、上の方で書いたように、もし環境を作っている途中であるならばwww無のサイトで統一を行った方がCNAMEレコードを設定でき、証明書関連で無駄な作業が減るのでお勧めというわけです。

一方で、私の場合は長い間www有でずっと統一してきましたが、このサイトをお名前ドットコムの機能でリダイレクトさせていたのと、長期間その方法で運用してきたので、サイトの書き換えも多少は必要な部分もあります。なので、手間を考えてもwww有に統一することにしました。

文字では書きましたが、実際にNGINXを使って同じ証明書を使ってhttpsかつwww有へリダイレクトさせると、異なった証明書が使用されている警告が出て、Googleでは危険なサイト扱いされてしまいました。

ですので、この場合にドメイン会社のサービスを使わず、Webサーバーのみを用いてリダイレクトを行うには、二つの証明書を用意して別々で認証する必要があります。

実際のNGINXの設定

それでは実際にNGINXに設定を行おうと思います。私はLet's Encryptを使っており、先にcertbotを使ってリダイレクトは考慮しないSSL化を行っていたので、それに追記していくような形で実装していきます。

まず、certbotを用いてwww無の証明書を発行してもらいます。

sudo certbot certonly --standalone -d www無ドメイン

このとき、80番ポートが使っていると怒られてしまった場合は、一度nginxっを停止させてしまいましょう。

sudo service nginx stop

この状態で上手くいけば問題ありません。

次に、正規化を行っていきます。実際の設定は以下のような感じにしました。certbotの作ったserverディレクティブが一番上にありますが、それは割愛して、実際に変更・追記した部分を掲載しておきます。

server {
    if ($host = www.thun-techblog.com) {
        return 301 https://www.thun-techblog.com$request_uri;
    } # managed by Certbot
    if ($host = thun-techblog.com) {
        return 301 https://www.thun-techblog.com$request_uri;
    } # Add by thun
        listen 80;
        listen [::]:80;
        server_name www.thun-techblog.com thun-techblog.com;
    return 404; # managed by Certbot
}

server {
    if ($host = thun-techblog.com) {
        return 301 https://www.thun-techblog.com$request_uri;
    } # managed by Certbot
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name thun-techblog.com;
        ssl_certificate /hoge/fullchain_key.huga;
        ssl_certificate_key /hoge/privkey_key.huga;
    return 404;
}

まず初めに、一つ目のserverディレクティブはcetbotのおかげで、www付きのサイトはhttps付きにリダイレクトされるようになっていたので、server_nameにwww無を追加し、そのリダイレクトを以下のコードで追加しています。

    if ($host = thun-techblog.com) {
        return 301 https://www.thun-techblog.com$request_uri;
    } # Add by thun

今回のようなwww有に統一するケースでは一つserverディレクティブを追加しています。

server {
    if ($host = thun-techblog.com) {
        return 301 https://www.thun-techblog.com$request_uri;
    } # managed by Certbot
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name thun-techblog.com;
        ssl_certificate /hoge/fullchain_key.caca;
        ssl_certificate_key /hoge/privkey_key.huga;
    return 404;
}

これでwwwなしのhttpsサイトを待ち受けている形になっており、www付きに301リダイレクトをしています。ここで、先ほどcertbotで生成した鍵を、ssl_certificateとssl_certificate_keyに指定します。

こうすることで、www無の証明書を指定できるので、怒られることなくリダイレクト可能になります。

更新が可能かどうかを調べてみましょう。

sudo certbot renew --dry-run

私の環境だとこの状態で実行したら以下のようなエラーが出て更新できませんでした。

Failed to renew certificate thun-techblog.com with error: Could not bind TCP port 80 because it is already in use by another process on this system (such as a web server). Please stop the program in question and then try again.

他のプロセスが80番ポートを使用しているから更新できないとのこと。どうしろと…?となるのですが、以下のコマンドとすることでエラーなく実行できました。

sudo certbot renew --dry-run --nginx

これで問題なく実行出来たら、crontabに以下のコマンドを追加します。

sudo crontab -u root -e
certbot renew --nginx

あとは更新がしっかりできていれば大丈夫ですが、実際に稼働させてみないと不安なので1か月後ぐらいにCAの期限を確認してみましょう。メールで更新結果を通達する方法もありますが、その説明は省きます。

まとめ

URLの正規化に関するお話でした。httpからhttpsへは非常に簡単なのですが、私のようなケースでCNAMEレコードが設定できない場合はhttps同士のリダイレクトはひと手間かかるというお話でした。今回は無料証明書なので気にすることはありませんが、有料証明書だと二つ証明書が必要になるのでコストがかさんでしまうかもしれません。

実態としては今後このような環境でしばらく運用するので、備忘録ついでという感じでもありますが、調べても簡単に出てこないことだったので、記事にしてみました。

それでは以上となります。お読みいただきありがとうございました。

投稿日:
カテゴリー: Linux

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です