通过ip访问nginx的服务时,被第一个server重定向了,通过设置default_server解决这个问题

Nginx default_server 指令完全指南

概述

在 Nginx 配置中,default_server 是一个非常重要但经常被忽视的参数。它用于指定当请求的 Host 头无法匹配任何 server_name 时,应该使用哪个 server 块来处理请求。

基本概念

什么是 default_server?

default_serverlisten 指令的一个参数,用于标记某个 server 块为默认服务器。当 Nginx 收到一个请求,但该请求的 Host 头(或IP地址访问)无法匹配任何已配置的 server_name 时,就会使用标记为 default_server 的 server 块来处理。

为什么需要 default_server?

在实际应用中,经常会遇到以下场景:

  1. IP地址直接访问:用户通过 IP 地址而不是域名访问服务器
  2. 错误的域名:用户输入了错误的域名或未配置的域名
  3. 恶意扫描:黑客通过 IP 扫描尝试探测服务器
  4. 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 块:

  1. 精确匹配 :完全匹配 server_name
  2. 通配符匹配 :使用通配符的 server_name(如 *.example.com
  3. 正则表达式匹配 :使用正则表达式的 server_name
  4. 默认服务器 :如果以上都不匹配,使用 default_server
  5. 第一个 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 配置中的重要参数,它可以:

  1. 防止配置错误:避免意外使用错误的 server 块
  2. 提升安全性:拒绝未知域名的访问请求
  3. 改善用户体验:为未配置的域名提供友好提示
  4. 简化调试:明确的默认行为使问题更容易定位

关键要点

  • 每个端口只能有一个 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 配置更加健壮、安全和易于维护。


参考资料:

相关推荐
2501_915918416 小时前
在 iOS 环境下查看 App 详细信息与文件目录
android·ios·小程序·https·uni-app·iphone·webview
2501_916007477 小时前
没有 Mac 用户如何上架 App Store,IPA生成、证书与描述文件管理、跨平台上传
android·macos·ios·小程序·uni-app·iphone·webview
夏幻灵19 小时前
HTTPS全面解析:原理、加密机制与证书体
ios·iphone
TheNextByte11 天前
如何在iPhone上恢复已删除的笔记的综合指南
笔记·ios·iphone
rose and war1 天前
python和jinja版本问题导致的访问报500
python·ios
fendoudexiaoniao_ios1 天前
iOS 列表拖拽cell排序
ios·swift
2501_915106321 天前
当 Perfdog 开始收费之后,我重新整理了一替代方案
android·ios·小程序·https·uni-app·iphone·webview
2501_915918411 天前
中小团队发布,跨平台 iOS 上架,证书、描述文件创建管理,测试分发一体化方案
android·ios·小程序·https·uni-app·iphone·webview
家里有只小肥猫1 天前
uniApp打包ios报错
ios·uni-app