nginx 子域名不正确地充当通配符?

nginx 子域名不正确地充当通配符?

我在 nginx 子域名方面遇到了一个奇怪的问题。首先,我的配置如下:

server {
    listen              443 ssl;
    server_name         secure.example.com;
    ssl_certificate     example.crt;
    ssl_certificate_key example.key;
    keepalive_timeout   70;

    location / {
        fastcgi_pass    127.0.0.1:8000;
        ...
    }
}

server {
    listen              80;
    server_name         example.com www.example.com;

    location / {
        fastcgi_pass    127.0.0.1:8000;
        ...
    }
}

我的想法是,我有一个安全域secure.example.com和一个普通域example.com。实际上,我可以转到https://example.comhttp://secure.example.com。我使用中间服务器解决了第二个问题:

server {
    listen              80;
    server_name         secure.example.com;
    rewrite     ^(.*)  https://secure.example.com$1 permanent;
}

但这不是最佳解决方案,我必须创建另一个解决方案来将 tld 上的 https 重定向到子域。如果我需要多个这样的服务器,我觉得我一定是做错了什么。为什么https://example.com当 443 上没有服务器监听时它会工作?它不应该只是连接失败吗?我相当困惑。

答案1

为什么https://example.com当没有服务器监听 443 时它还能工作?难道它不应该连接失败吗?

server_name在 80/tcp (HTTP) 或 443/tcp (HTTPS) 上建立连接后,将评估 (或更准确地说是 HTTP/1.1 Host 标头)。这意味着,如果和secure.example.com具有example.com相同的 A 资源记录 (它们指向相同的 IP 地址),则在建立连接并发送 HTTP/1.1 Host 标头之前,无法判断客户端想要查看哪个虚拟主机。

更准确地说,TCP/IP 使用 IP 地址(IP 部分)和端口(TCP 部分)。因此,如果你将某个进程(例如 nginx)绑定到某个 IP 地址和端口,它将始终在此套接字上应答,而 TCP/IP 对 HTTP/1.1 及其 Host 标头一无所知。

如果你想简化你的 nginx 配置,你可以编写以下内容:

server {
    listen              443 ssl;
    listen              80;

    server_name         secure.example.com;
    ssl_certificate     example.crt;
    ssl_certificate_key example.key;
    keepalive_timeout   70;

    if ($scheme = http) {
        rewrite  ^(.+)$  https://example.com$1  redirect;            
    }

    location / {
        fastcgi_pass    127.0.0.1:8000;
        # ...
    }
}

server {
    listen              80;
    server_name         example.com www.example.com;

    location / {
        fastcgi_pass    127.0.0.1:8000;
        # ...
    }
}

答案2

看看 Nginxserver_name 文档。它表示如果虚拟主机列表中没有任何匹配项,则 nginx 将使用第一个服务器 {}匹配的块指示。

如果你想强迫用户使用secure.example.com主办https,您可以采用与相反情况相同的解决方法。

相关内容