Nginx 的一个 SSL 服务器会干扰所有其他 http 服务器

Nginx 的一个 SSL 服务器会干扰所有其他 http 服务器

我遇到了一个奇怪的问题。我有一个带有许多普通 http(端口 80)虚拟服务器的 nginx。它是 apache 的反向代理。现在我只需要添加一个 https(443,SSL)服务器。我将其作为一个单独的虚拟服务器来执行,它运行良好,但有一个令人讨厌的副作用。当我尝试使用 https(它们没有)访问其他虚拟服务器时,我会从具有该 SSL 证书的服务器获得响应。

例子:

server {
     server_name domain1.com

    ssl on;
    ssl_certificate           ...;
    ssl_certificate_key       ...;

    root /hosts/domain1.com/htdata;
    set $myport 17096;
    include /hoster/sites/proxies/_base_ssl;
}

server {
    server_name domain2.com
    root /hosts/domain2.com/htdata;
    set $myport 17009;

    include /hoster/sites/proxies/_base;
}

现在当我这样做https://domain2.com我收到了来自服务器 domain1.com 的响应,但浏览器只是说证书不适用于此域。这是真的。然而,糟糕的是,搜索引擎忽略了证书的域不匹配,并https://domain2.com一面镜子https://domain1.com

然后我决定添加一个默认的 SSL 服务器,它将捕获不需要的 SSL 连接:

server {
    listen 80 default_server accept_filter=httpready backlog=1024;
    listen 443 ssl;
...
}

但由于没有证书,因此应该会导致错误。我同意。

这完全终止了 SSL 连接。现在我无法连接到https://domain1.com 太!!!似乎默认服务器捕获了所有 SSL 连接,因为我在错误日志中看到很多这样的消息:

2018/07/06 19:42:11 [错误] 27792#100278: *134 SSL 握手时监听 SSL 端口的服务器中未定义“ssl_certificate”,客户端:94.25.168.7,服务器:0.0.0.0:443

嗯,我以为 SNI 可能不起作用,但是

root@shu:/hoster/sites/proxies # nginx -V
nginx version: nginx/1.12.2
built with OpenSSL 1.0.1u-freebsd  22 Sep 2016
TLS SNI support enabled
configure arguments: --prefix=/usr/local/etc/nginx --with-cc-opt='-I /usr/local/include' --with-ld-opt='-L /usr/local/lib' --conf-path=/usr/local/etc/nginx/nginx.conf --sbin-path=/usr/local/sbin/nginx --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --user=www --group=www --modules-path=/usr/local/libexec/nginx --with-file-aio --with-cc-opt='-DNGX_HAVE_INET6=0 -I /usr/local/include' --with-threads --without-mail_imap_module --without-mail_pop3_module --without-mail_smtp_module --http-client-body-temp-path=/var/tmp/nginx/client_body_temp --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi_temp --http-proxy-temp-path=/var/tmp/nginx/proxy_temp --http-scgi-temp-path=/var/tmp/nginx/scgi_temp --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi_temp --http-log-path=/var/log/nginx/access.log --with-http_gunzip_module --with-http_realip_module --with-pcre --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_v2_module --with-stream_ssl_module --with-stream=dynamic

我究竟做错了什么?

按要求添加:

_根据

listen 80;
#    listen 443 ssl;

location / {
   include proxy.conf;
   proxy_pass http://$apacheip:$myport;
}

location @apachesite {
    include proxy.conf;
    proxy_pass http://$apacheip:$myport;
}

_base.ssl

listen 443 ssl;

location / {
   include proxy.conf;
   proxy_pass http://$apacheip:$myport;
}

location @apachesite {
    include proxy.conf;
    proxy_pass http://$apacheip:$myport;
}

代理配置

proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 0;
client_body_buffer_size 1m;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;
pro xy_http_version 1.1;

答案1

Nginx 首先根据 host:port 选择虚拟主机服务器,然后根据 name/sni 选择。下面是您所拥有的虚拟主机的粗略树状图

  • 听众:
    • [::]:80
      • HTTP
        • (nameless) 默认服务器
        • domain1.com
    • [::]:443
      • HTTPS
        • (nameless) 1
        • domain2.com

1无名服务器仅默认为80,不默认为443(https)

当您使用 domain1.com 的 SNI/Host 以 443(https)方式访问服务器时,由于没有匹配项,因此会恢复为默认值,并且由于该主机:端口组合没有列出默认值,因此它会恢复为使用配置中包含的第一个行为(在本例中可能是 domain2)

根据经验法则,您应该确保您的默认服务器在您监听的所有端口上都有 default_server,这也是放置 nginx 监听参数的方便位置,因为其中许多参数只能指定一次。

我不确定当证书丢失且没有默认值时 nginx 的行为,因此您可能需要为其生成一个自签名占位符,或者通过 let's encrypt 颁发证书作为权宜之计。(即使只是重定向回普通的旧 http。)

相关内容