Nginx default_server 指令完全指南
概述
在 Nginx 配置中,default_server 是一个非常重要但经常被忽视的参数。它用于指定当请求的 Host 头无法匹配任何 server_name 时,应该使用哪个 server 块来处理请求。
基本概念
什么是 default_server?
default_server 是 listen 指令的一个参数,用于标记某个 server 块为默认服务器。当 Nginx 收到一个请求,但该请求的 Host 头(或IP地址访问)无法匹配任何已配置的 server_name 时,就会使用标记为 default_server 的 server 块来处理。
为什么需要 default_server?
在实际应用中,经常会遇到以下场景:
- IP地址直接访问:用户通过 IP 地址而不是域名访问服务器
- 错误的域名:用户输入了错误的域名或未配置的域名
- 恶意扫描:黑客通过 IP 扫描尝试探测服务器
- DNS配置错误:域名解析配置错误导致Host头不匹配
如果没有明确指定 default_server,Nginx 会使用监听该端口的第一个 server 块作为默认服务器,这可能导致意外的行为。
语法
listen port [default_server];
常见用法
# HTTP (端口 80)
listen 80 default_server;
# HTTPS (端口 443)
listen 443 ssl default_server;
# 同时指定监听地址和端口
listen 192.168.1.100:80 default_server;
# IPv6
listen [::]:80 default_server;
实际应用场景
场景 1:防止域名劫持重定向
问题场景:
假设您的 Nginx 配置如下:
http {
# 第一个 server 块 - 域名重定向
server {
listen 80;
server_name example.com;
return 301 https://example.com$request_uri;
}
# 第二个 server 块 - 实际服务
server {
listen 80;
server_name localhost;
root /var/www/html;
index index.html;
}
}
当用户通过 IP 地址访问(如 http://192.168.1.100/)时,由于没有匹配的 server_name,Nginx 会使用第一个 server 块,导致被重定向到 https://example.com,这显然不是我们想要的结果。
解决方案:
http {
# 域名重定向
server {
listen 80;
server_name example.com;
return 301 https://example.com$request_uri;
}
# 设置为默认服务器
server {
listen 80 default_server;
server_name localhost;
root /var/www/html;
index index.html;
}
}
场景 2:安全防护 - 拒绝未知域名访问
出于安全考虑,您可能希望拒绝所有未明确配置的域名访问:
http {
# 默认拒绝访问
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# 返回 444 表示直接关闭连接
return 444;
}
# 您的实际网站
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example;
index index.html;
}
}
场景 3:提供友好的错误页面
为未知域名提供一个友好的提示页面:
http {
# 默认服务器 - 显示友好提示
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /var/www/default;
location / {
return 200 "您访问的域名未在本服务器配置。\n";
add_header Content-Type "text/plain; charset=utf-8";
}
}
# 实际网站
server {
listen 80;
server_name example.com;
root /var/www/example;
}
}
场景 4:多域名多服务器环境
在托管多个网站的服务器上,明确指定默认服务器可以避免配置错误:
http {
# 网站 A
server {
listen 80;
server_name site-a.com www.site-a.com;
root /var/www/site-a;
}
# 网站 B
server {
listen 80;
server_name site-b.com www.site-b.com;
root /var/www/site-b;
}
# 开发测试环境 - 默认服务器
server {
listen 80 default_server;
server_name localhost;
root /var/www/dev;
location / {
index index.html;
}
}
}
工作原理
Nginx 匹配顺序
当 Nginx 接收到一个 HTTP 请求时,会按以下顺序匹配 server 块:
- 精确匹配 :完全匹配
server_name - 通配符匹配 :使用通配符的
server_name(如*.example.com) - 正则表达式匹配 :使用正则表达式的
server_name - 默认服务器 :如果以上都不匹配,使用
default_server - 第一个 server 块 :如果没有指定
default_server,使用该端口的第一个 server 块
验证当前配置
可以通过以下命令查看 Nginx 如何处理不同的 Host 头:
# 测试通过 IP 访问
curl -H "Host: 192.168.1.100" http://192.168.1.100/
# 测试未配置的域名
curl -H "Host: unknown-domain.com" http://192.168.1.100/
# 查看 Nginx 的请求日志
tail -f /var/log/nginx/access.log
重要注意事项
1. 每个端口只能有一个 default_server
# ❌ 错误:同一个端口不能有多个 default_server
server {
listen 80 default_server;
server_name example1.com;
}
server {
listen 80 default_server; # 这会报错!
server_name example2.com;
}
如果尝试这样配置,Nginx 会报错:
nginx: [emerg] duplicate default server for 0.0.0.0:80
2. 不同端口可以有不同的 default_server
# ✅ 正确:不同端口可以各有一个 default_server
server {
listen 80 default_server;
server_name localhost;
}
server {
listen 443 ssl default_server;
server_name localhost;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
}
3. IPv4 和 IPv6 需要分别指定
server {
listen 80 default_server; # IPv4
listen [::]:80 default_server; # IPv6
server_name localhost;
}
4. SSL/TLS 配置注意事项
HTTPS 的 default_server 需要提供有效的 SSL 证书:
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;
}
最佳实践
1. 总是明确指定 default_server
不要依赖 Nginx 的隐式行为(使用第一个 server 块),应该明确指定:
server {
listen 80 default_server;
server_name _;
return 444; # 拒绝未配置的域名
}
2. 使用下划线作为占位符
server_name _; 是一个特殊值,表示"捕获所有不匹配的域名":
server {
listen 80 default_server;
server_name _; # 下划线表示占位符,不代表实际域名
return 444;
}
3. 在配置文件顶部定义 default_server
将 default_server 放在配置文件的前面,使配置结构更清晰:
http {
# 首先定义默认服务器
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
# 然后是具体的网站配置
server {
listen 80;
server_name example.com;
# ...
}
}
4. 分离 HTTP 和 HTTPS 的 default_server
# HTTP 默认服务器
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
# 可以选择重定向到 HTTPS 或直接拒绝
return 301 https://$host$request_uri;
}
# HTTPS 默认服务器
server {
listen 443 ssl default_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;
}
5. 记录日志用于调试
server {
listen 80 default_server;
server_name _;
# 记录访问日志,便于发现异常流量
access_log /var/log/nginx/default-access.log;
error_log /var/log/nginx/default-error.log;
return 444;
}
实战案例
案例:开发环境配置
http {
# 生产环境 - 正式域名
server {
listen 80;
server_name example.com www.example.com;
root /var/www/production;
location / {
index index.html;
}
}
# 测试环境 - 子域名
server {
listen 80;
server_name test.example.com;
root /var/www/testing;
}
# 开发环境 - 默认服务器(通过 IP 访问)
server {
listen 80 default_server;
server_name localhost;
root /var/www/development;
# 显示服务器信息(仅开发环境)
add_header X-Server-Type "Development";
location / {
autoindex on; # 开启目录浏览
}
}
}
案例:安全加固配置
http {
# 默认拒绝未知请求
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
# 自签名证书(用于 HTTPS)
ssl_certificate /etc/nginx/ssl/dummy.crt;
ssl_certificate_key /etc/nginx/ssl/dummy.key;
# 记录可疑访问
access_log /var/log/nginx/suspicious.log;
# 返回最小化响应
return 444;
}
# 真实网站配置
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# 强制 HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example;
index index.html;
}
}
调试技巧
1. 测试配置是否生效
# 检查配置语法
nginx -t
# 重新加载配置
nginx -s reload
# 测试不同的 Host 头
curl -H "Host: example.com" http://your-server-ip/
curl -H "Host: unknown.com" http://your-server-ip/
curl http://your-server-ip/ # 使用 IP 直接访问
2. 查看当前监听端口
# 查看 Nginx 监听的端口
netstat -tlnp | grep nginx
# 或使用 ss 命令
ss -tlnp | grep nginx
3. 查看 Nginx 错误日志
# 实时查看错误日志
tail -f /var/log/nginx/error.log
# 查看最近的错误
tail -n 100 /var/log/nginx/error.log
常见错误及解决方案
错误 1:重复的 default_server
错误信息:
nginx: [emerg] duplicate default server for 0.0.0.0:80 in /etc/nginx/sites-enabled/site.conf:10
原因: 同一个端口配置了多个 default_server
解决方案: 检查所有配置文件,确保每个端口只有一个 default_server:
# 搜索所有 default_server 配置
grep -r "default_server" /etc/nginx/
错误 2:SSL 证书问题
错误信息:
nginx: [emerg] SSL_CTX_use_certificate_chain_file() failed
原因: HTTPS 的 default_server 没有配置有效的证书
解决方案: 为 default_server 提供证书(可以是自签名证书):
# 生成自签名证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/default.key \
-out /etc/nginx/ssl/default.crt
错误 3:配置未生效
问题: 修改了配置但 default_server 行为未改变
解决方案:
# 1. 检查配置语法
nginx -t
# 2. 如果语法正确,重新加载配置
nginx -s reload
# 3. 如果还是不行,重启 Nginx
systemctl restart nginx
# 4. 清除浏览器缓存后重试
性能考虑
使用 default_server 本身对性能影响很小,但可以通过以下方式优化:
1. 减少不必要的处理
server {
listen 80 default_server;
server_name _;
# 直接关闭连接,不做任何处理
return 444;
}
2. 限制连接速率
# 定义限速区域
limit_req_zone $binary_remote_addr zone=default_limit:10m rate=10r/s;
server {
listen 80 default_server;
server_name _;
# 应用限速
limit_req zone=default_limit burst=20;
return 444;
}
总结
default_server 是 Nginx 配置中的重要参数,它可以:
- 防止配置错误:避免意外使用错误的 server 块
- 提升安全性:拒绝未知域名的访问请求
- 改善用户体验:为未配置的域名提供友好提示
- 简化调试:明确的默认行为使问题更容易定位
关键要点
- 每个端口只能有一个
default_server - IPv4 和 IPv6 需要分别指定
- HTTPS default_server 需要提供 SSL 证书
- 建议明确指定而不是依赖隐式行为
- 使用
server_name _作为占位符
推荐配置模板
http {
# HTTP 默认服务器
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
# HTTPS 默认服务器
server {
listen 443 ssl default_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;
}
# 您的实际网站配置
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# ...
}
}
正确使用 default_server 可以让您的 Nginx 配置更加健壮、安全和易于维护。
参考资料: