Nginxのバーチャルサーバーを設定した時の直IP接続を拒否する方法

Nginxにバーチャルサーバーの設定をすると複数のドメインのサイトを1台のウェブサーバーで運用することができます。ただDNSでの名前解決をせずIPを直指定してウェブサーバーにアクセスすることもできてしまうので、これを防ぐ方法です。ベストな方法ではないのかもしれませんので、参考程度に見てください。

ドメインが example01.com と example02.com である2つのサイトを運用しているサーバー(IPアドレスは 210.100.1.1 )の例です。

この場合のNginxのconfファイルは以下のように設定をします。


server {
    listen       80;
    server_name  www.dummy.com;
     :
    location / {
        return 444;
    }
}

server {
    listen 80;
    server_name www.example01.com;
    return 301 https://$host$request_uri;
}

server {
    listen 80;
    server_name www.example02.com;
    return 301 https://$host$request_uri;
}

server {
    listen       443 ssl;
    server_name  www.dummy.com;

    ssl_certificate ・・
    ssl_certificate_key ・・

    location / {
        return 444;
    }
     :
}

server {
    listen       443 ssl;
    server_name  www.example01.com;

    ssl_certificate ・・
    ssl_certificate_key ・・
     :
}

server {
    listen       443 ssl;
    server_name  www.example02.com;

    ssl_certificate ・・
    ssl_certificate_key ・・
     :
}

example01.com と example02.com のドメイン以外にダミーのドメイン www.dummy.com の設定をします。ダミードメインは example01.com と example02.com より先に記載しておきます。これはリクエストがどのバーチャルサーバーにも合致しない際にダミードメインがデフォルトサーバーとして振る舞うためです。デフォルトサーバーはlistenディレクティブにdefault_serverパラメータで明示的に指定できるのですが、今回は記載順で対応しました。

ダミードメインのlocationディレクティブには return 444 を設定します。このリターンコードはNginx独自のものでウェブブラウザとの切断になります。

HTTPSのダミードメインの部分ですが証明書の記載が必要です。これを記載しないとコンフィグチェック nginx -t でエラーになってしまいます。ですが証明書などはないので ssl_certificate と ssl_certificate_key には自己署名証明書(オレオレ証明書)を設定しました。

この設定で実際に直IPを指定してFirefoxでウェブサイトにアクセスしてみると「警告:潜在的なセキュリティリスクあり」と表示されます。

①詳細へ進む.. を押下すると「自己署名をしているためこの証明書は信頼されません」と表示されます。さらに、②危険性を承知の上で使用 を押下すると該当のサイトのページに遷移するのですが、locationディレクティブには return 444 を設定しているのでサーバーとの通信は切断されます。そのため「安全な接続ができませんでした」の画面になります。

なお先ほどの警告の画面で ③証明書を確認 を押下すると証明書の確認ができます。自己署名証明書なのでコモンネームが www.dummy.com のものとなっています。

Firefoxの場合ですが、サーバー証明書のエラー例外は設定から「プライバシーとセキュリティ」→「証明書を表示..」で確認できます。

Let’s Encryptのサーバー証明書を使っている場合の話となりますが、今回のNginxのconfファイルの設定だと certbot renew コマンドが失敗します。バーチャルサーバーの設定の影響で失敗するのかはわかりません。単一ドメインで certbot renew を実行すれば成功するのでやり方を書いておきます。

/etc/letsencrypt/renewal 配下には各ドメインのconfファイルがあるかと思います。このうち証明書を更新するほうはそのままで、更新しないほうのconfファイルをリネームします。この作業はroot権限が必要です。example01.com を更新する場合です。

変更前
example01.com.conf
example02.com.conf

変更後
example01.com.conf
example02.com.conf.bk

Nginxのconfファイルですがバーチャルサーバーの設定を全部なくします。example01.com を更新する場合です。


server {
    listen 80;
    server_name www.example01.com;
    return 301 https://$host$request_uri;
}

server {
    listen       443 ssl;
    server_name  www.example01.com;

    ssl_certificate ・・
    ssl_certificate_key ・・
     :
}

Nginxでconfファイルのリロードを行ってから certbot renew をすれば、うまくいきます。証明書の更新が終わったら、もとに戻しておきましょう。

自己署名証明書(別名はオレオレ証明書)を作成してみた。

HTTPS通信の際に使用するサーバー証明書は認証局の署名が必要です。自身で署名したものを自己署名証明書と言います。自分で認証するのでオレオレ証明書とも呼ばれています。自己署名証明書を作ってみたので、そのやり方を書いておきます。

実施した環境はCentOS7でOpenSSLがインストール済みです。

まずは、秘密鍵を作成します。

$ openssl genrsa -out server.key

opensslコマンドのオプションの意味です。

  • genrsa・・・ RSA秘密鍵を作成します。
  • -out・・・出力ファイルの指定をします。

鍵長はデフォルトでは2048bitです。ローカルディレクトリに server.key という名前の秘密鍵が作成されます。

次に、証明書署名要求(Certificate Signing Request)の作成を行います。証明書署名要求はCSRとも呼ばれます。

$ openssl req -new -key server.key -out server.csr

  • req・・・ 証明書署名要求の処理を行います。
  • -new・・・ 新しい証明書要求を生成します。
  • -key・・・ 秘密鍵を指定します。
  • -out・・・出力ファイルの指定をします。

CSRは認証局の署名のない状態のサーバー証明書です。秘密鍵から公開鍵の生成は可能でCSRには公開鍵が含まれます。通常のサーバー証明書はこのCSRを認証局に提出して、公開鍵が正当なものであるという署名をしてもらいます。

なお、CSRの作成時は対話形式となり入力が必要になります。自己署名証明書であれば入力が必要なものは Common Name のところで他のものは未入力(リターンキーの押下)で構いません。Common Name には www.dummy.com と入力しています。以下は実行時のものです。


$ openssl req -new -key server.key -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:www.dummy.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:

ローカルディレクトリに server.csr という名前の証明書署名要求が作成されます。

最後に、証明書署名要求に署名をします。自分の秘密鍵を使って署名する(自分で認証していると言い張る)のでオレオレ証明書とも呼ばれるのだと思います。

$ openssl x509 -req -days 3650 -signkey server.key -in server.csr -out server.crt

  • x509・・・ X.509のフォーマットでサーバー証明書を作成します。
  • -req・・・ 証明書署名要求の読み取りをします。
  • -days・・・ 証明書の有効期限の日数を指定します。
  • -signkey・・・証明書に署名する秘密鍵を指定します。
  • -in・・・ 読み取る証明書署名要求を指定します。
  • -out・・・出力ファイルの指定をします。

-signkey オプションで指定する秘密鍵は通常は認証局の秘密鍵ですが、自己署名証明書の場合は自分の秘密鍵です。ローカルディレクトリに server.crt という名前のサーバー証明書が作成されます。

このサーバー証明書と秘密鍵をウェブサーバーに設定するとHTTPS通信が可能になります。Nginxの場合は ssl_certificate ディレクィブと ssl_certificate_key ディレクィブになります。