Nginx禁止未绑定域名或IP访问80和443端口实践小结
前言
nginx在决定请求由哪个server块执行时,主要关注的是server块中的listen和server_name两个字段,如果根据listen指令无法得到最佳匹配,将会开始解析server_name指令。nginx会检查请求中的”Host”头,这个值包含了客户端实际试图请求的域名或者ip地址。nginx会根据这个值去匹配server_name指令,匹配规则会在文章中详细描述。其中有一个需要大家注意的地方是如果没有匹配到任何规则的话,则会选择可用列表中的第一个server,带来的问题就是未绑定域名或IP直接访问80和443端口会给后端逻辑服务增加压力并产生不合理的错误日志,合适的解决办法是通过在nginx的server块中添加default_server禁止未绑定域名或IP访问80和443端口过滤不合理的流量。
Nginx禁止未绑定域名或IP访问80和443端口实践小结
更新历史
2020年02月26日 - 初稿
阅读原文 - https://wsgzao.github.io/post/nginx-default-server/
Server_name指令
如果根据listen指令无法得到最佳匹配,将会开始解析server_name指令.nginx会检查请求中的”Host”头,这个值包含了客户端实际试图请求的域名或者ip地址.nginx会根据这个值去匹配server_name指令,匹配规则如下:
- nginx会尝试寻找一个和sever_name和Host值完全匹配的server块,如果找到多个精确匹配,则会使用第一个匹配的server块
- 如果没有找到精确匹配的server块,则nginx尝试找到server_name带有*开头的server块,如果找到多个,则选择最长匹配的server块
- 如果没有找到使用开头的server块,则会寻找以结尾的server块,同样,如果有多个匹配, 选择最长匹配
- 如果没有找到使用*匹配的server块,则会寻找使用正则表达式(以~开头)定义server_name的server块,如果找到多个匹配,会使用第一个匹配
- 如果没有找到正则表达式匹配的server块,则nginx将会选择一个匹配listen字段的default server块.每一个ip和端口组合都可以配置一个且只能配置一个默认的default_server块,如果没有的话,则会选择可用列表中的第一个server
示例如下:
(1)准确的server_name匹配,例如:
1 | server { |
(2)以*通配符开始的字符串:
1 | server { |
(3)以*通配符结束的字符串:
1 | server { |
(4)匹配正则表达式:
1 | server { |
(5)如果以上都没有匹配,则使用default_server.如果没有指定default_server,则会选择第一个可用的server.我们可以指定对于没有匹配的host值时,返回错误到客户端.可以用来防止别人把垃圾流量转到你的网站。
1 | server { |
通过返回444这个nginx的非标准错误码让nginx断开与浏览器的连接
Nginx官方对default_server的解释
Miscellaneous names
If someone makes a request using an IP address instead of a server name, the “Host” request header field will contain the IP address and the request can be handled using the IP address as the server name:
1 | server { |
In catch-all server examples the strange name “_” can be seen:
1 | server { |
There is nothing special about this name, it is just one of a myriad of invalid domain names which never intersect with any real name. Other invalid names like “–” and “!@#” may equally be used.
Name-based virtual servers
nginx first decides which server should process the request. Let’s start with a simple configuration where all three virtual servers listen on port *:80:
1 | server { |
In this configuration nginx tests only the request’s header field “Host” to determine which server the request should be routed to. If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port. In the configuration above, the default server is the first one — which is nginx’s standard default behaviour. It can also be set explicitly which server should be default, with the default_server parameter in the listen directive:
1 | server { |
The default_server parameter has been available since version 0.8.21. In earlier versions the default parameter should be used instead.
Note that the default server is a property of the listen port and not of the server name. More about this later.
How to prevent processing requests with undefined server names
If requests without the “Host” header field should not be allowed, a server that just drops the requests can be defined:
1 | server { |
Here, the server name is set to an empty string that will match requests without the “Host” header field, and a special nginx’s non-standard code 444 is returned that closes the connection.
Since version 0.8.48, this is the default setting for the server name, so the server_name “” can be omitted. In earlier versions, the machine’s hostname was used as a default server name.
nginx禁止未绑定域名或IP访问80和443端口实践
Nginx uses ‘Host’ header for server_name matching. It does not use TLS SNI. This means that for an SSL server, nginx must be able to accept SSL connection, which boils down to having certificate/key. The cert/key can be any, e.g. self-signed.
1 | server { |
详细的配置步骤
1 | # 未设置default_server,会根据列表第一个server服务,产生垃圾流量 |