我在 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.com
和http://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,您可以采用与相反情况相同的解决方法。