XXX.XXX.XXX.XXX mysite.com
という A レコードを持つサイトを運用していて、http と https でのアクセスを受け付けているとします。
Nginx では下記のようなサーバブロックがあるイメージです。
server { listen 80; server_name mysite.com; return 301 https://$server_name$request_uri; #https にリダイレクト } server { listen 443 ssl; server_name mysite.com; … }
そして IP 直指定で飛んでくる不審なリクエストには応答したくないので Nginx 内の公式ドキュメント Server names を参考に下記のようなサーバブロックを追加してみます。
server { listen 80 default_server; server_name _; return 444; }
このとき、当然 http://XXX.XXX.XXX.XXX
へのリクエストには 444 が返るのですが、https://XXX.XXX.XXX.XXX
は SSL 証明書の警告が出るもののアクセスできてしまいます。
How nginx processes a request によれば
もし “Host” ヘッダがどのサーバ名ともマッチしない場合、またはリクエストにこのフィールドがまったく含まれていない場合は、nginxはこのリクエストをデフォルトサーバに振り向けます。上記の設定ではデフォルトサーバは最初のもので、これは nginx の標準的なデフォルトの挙動です。
ということで 443 に対するディレクティブが mysite.com のものしかない場合、https へのリクエストは全て mysite.com のサーバブロックで処理してしまうようです。
では、80 に加えて 443 に対する default_server も足してみると良さそうです。
server { listen 80 default_server; server_name _; return 444; } server { listen 443 ssl default_server; server_name _; ssl_certificate /path/to/mysite.crt ssl_certificate_key /path/to/mysite.key return 444; }
最初、https://mysite.com へのリクエストまでもが 444 でドロップしてしまっていたのですが ssl_certificate と ssl_certificate_key を記載していなくて
no "ssl_certificate" is defined in server listening on SSL port while SSL handshaking, client: x.x.x.x, server: 0.0.0.0:443
とエラーになっていただけでした。このデフォルトサーバの証明書はオレオレでも構わないと思います。
あるいは
の回答にあるような
server { listen 443; server_name mysite.com; if ($host != "mysite.com") { return 444; } ... }
でも IP 直のアクセスを落とすことができますが、server_name を指定しているのにもう一度チェックしていて若干冗長な感じがあります。
あとこちらでは前段に HAproxy を置いてそこで落としているようです。
今回のサイトは IP とドメインが1対1なので SNI 云々については気にする必要がありませんでしたが、複数ドメインをホストするようなサービスだと default_server での直 IP リクエストドロップが良さそうです。