nginx如何防止非 server_name 配置的域名访问
目录
在 Nginx 中,如果客户端请求的域名未在 server_name 指定的配置中匹配,Nginx 仍然会将请求转发到默认的 server 块。为了防止非 server_name 配置的域名访问,可以使用以下几种方法:
方法 1:使用默认 server 块拦截未匹配的域名
在 Nginx 配置文件中(通常是 /etc/nginx/nginx.conf 或 /etc/nginx/conf.d/default.conf),添加一个默认的 server 块,只允许 server_name 明确配置的域名访问,其他所有未匹配的域名都返回 444(直接断开连接)。
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}解释
listen 80 default_server;:表示该server块是默认的服务器,所有未匹配的请求都会进入这里。server_name _;:这个_是一个通配符,表示未匹配的任何域名都会进入该server块。return 444;:返回 444 状态码,直接断开连接,不给客户端任何响应,提高安全性。
方法 2:使用 if 语句在特定 server 块中拦截
如果不想使用默认 server 块,也可以在你的业务 server 块中检查 Host 头,拒绝非指定域名的访问。
server {
listen 80;
server_name example.com www.example.com;
if ($host !~* ^(example\.com|www\.example\.com)$) {
return 403;
}
location / {
proxy_pass http://127.0.0.1:8080;
}
}解释
if ($host !~* ^(example\.com|www\.example\.com)$):检查Host头,如果不符合example.com或www.example.com,则返回403 Forbidden。return 403;:拒绝访问。
⚠️ 注意:Nginx 官方不推荐 if 语句用于控制访问,但在简单场景下可以使用。
方法 3:监听特定 IP,限制非指定域名访问
如果服务器有多个 IP,可以让 Nginx 只监听特定 IP,并通过 server_name 控制。
server {
listen 80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
server {
listen 80;
server_name _; # 未匹配的所有请求
return 444; # 直接断开连接
}方法 4:针对 HTTPS 限制非 server_name 访问
如果使用 HTTPS,并且不希望未配置的域名访问你的服务器,可以使用以下方式:
server {
listen 443 ssl default_server;
server_name _;
ssl_certificate /etc/nginx/ssl/default.crt;
ssl_certificate_key /etc/nginx/ssl/default.key;
return 444;
}解释
- 让
default_server处理所有未匹配的域名。 - 使用一个默认的 SSL 证书(可以是一个无效或自签名证书)。
- 直接返回
444,防止服务器暴露给未授权的访问者。
如何生成自签名 SSL 证书?
mkdir -p /etc/nginx/ssl
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/default.key \
-out /etc/nginx/ssl/default.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Default/CN=default"总结
如果希望完全禁止未配置 server_name 的域名访问,推荐使用 方法 1(默认 server 块拦截)或 方法 3(监听特定 IP),它们是 Nginx 官方推荐的方式,性能最好,配置最清晰。
如果有更复杂的需求(如某些域名返回 403,其他域名正常访问),可以使用 方法 2(if 语句检查 $host)。对于 HTTPS,使用 方法 4 结合默认 server 块。