我有几台服务器在同一台机器上运行,一些只使用http,一些使用http和https。 有几个服务器块定义在主configuration文件中包含的单独文件中。
我为httpbuild立了一个“默认”服务器,这个服务器将为通用的“维护页面”提供与其他configuration文件中其他服务器名称不匹配的请求。 http缺省服务器按预期工作,它使用server_name“_”,它首先出现在包含列表中(因为我已经观察到,在服务器间重复server_name的情况下,首先使用的是一个)。 这很好。
我期望相同的确切的服务器块(只有切换“听80默认服务器”“听443默认服务器”,而不是服务页面“返回444”),但事实并非如此。 相反,新的默认https服务器实际上是抓取所有传入的https连接并导致它们失败,尽pipe其他服务器块为传入请求提供了更合适的server_name。 删除新的默认https服务器将导致恢复半正确的行为:带有https的网站将全部正确加载; 但没有HTTPS的网站都将被路由到包含文件中的第一个HTTPS服务器(根据文档,如果没有“default_server”出现,那么出现的第一个服务器块将是“默认”)。
所以我的问题是,什么是正确的方式来定义一个“默认服务器”在Nginx的SSL连接? 为什么当我明确地设置一个“default_server”时,它变得贪婪并且抓住所有的连接,而当我隐式地让nginx决定“默认服务器”时,它就像我所期望的那样工作(把不正确的服务器设置为默认服务器,行为正确)?
这是我的“默认服务器”。 Http工作而不破坏其他服务器。 Https打破其他服务器,并消耗所有。
server { listen 443 ssl default_server; server_name _; access_log /var/log/nginx/maintenance.access.log; error_log /var/log/nginx/maintenance.error.log error; return 444; } server { listen *:80 default_server; server_name _; charset utf-8; access_log /var/log/nginx/maintenance.access.log; error_log /var/log/nginx/maintenance.error.log error; root /home/path/to/templates; location / { return 503; } error_page 503 @maintenance; location @maintenance { rewrite ^(.*)$ /maintenance.html break; } }
你们中的任何一个人看到这里可能是错的?
您的“默认”https块中没有定义任何ssl_certificate或ssl_certificate_key。 虽然你没有或者想要这个默认场景的一个真正的关键,你仍然需要configuration一个,否则nginx会有你描述的不受欢迎的行为。
创build一个通用名称为*的自签名证书,并将其插入到您的configuration中,并将开始按您的要求工作。
在这个设置下的“默认”行为将是一个浏览器会得到一个警告,证书不能被信任,如果用户添加证书作为例外,连接将被nginx丢弃,他们将看到他们的浏览器的默认“无法连接”错误信息。
我们基本上要避免不惜一切代价,将我们的configuration文件中的第一个服务器定义作为SSL连接的全部服务器。 我们都知道它是这样做的(相反,http和使用default_serverconfiguration,很好地工作)。
SSL(尚未)声明性地实现,所以我们必须编写一个IF …
variables$host
是来自请求行或http头的主机名。 variables$server_name
是我们现在所在的服务器块的名称。
所以,如果这两个不相等,那么你服务这个SSL服务器块为另一个主机,所以应该被阻止。
该代码不包含对您的服务器IP地址的特定引用,因此可以轻松地将其重用于其他服务器configuration,而无需进行修改。
例:
server { listen 443 ssl http2; listen [::]:443 ssl http2; ### ### Section: SSL # ## Check if this certificate is really served for this server_name ## http://serverfault.com/questions/578648/properly-setting-up-a-default-nginx-server-for-https if ($host != $server_name) { #return 404 "this is an invalid request"; return 444; } ...
我设法使用nginx在单个IP上configuration一个共享的专用主机。 默认的HTTP和HTTPS为未知域的传入提供404服务。
1 – 创build一个默认区域
由于nginx以ascii的顺序加载虚拟主机,所以你应该在/etc/nginx/sites-enabled
创build一个00-default
文件/符号链接。
2 – 填写默认区域
用默认的虚拟主机填充你00-default
。 这是我正在使用的区域:
server { server_name _; listen 80 default_server; return 404; } server { listen 443 ssl; server_name _; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; return 404; }
3 – 创build自签名的证书,testing和重新加载
您需要在/etc/nginx/ssl/nginx.crt
创build一个自签名证书。
创build一个默认的自签名证书: sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt
只是提醒 :
nginx -t
sudo service nginx reload
希望它有帮助。
如果你想绝对确定,那么对不应该在HTTPS和主机上应答的主机使用单独的IP地址。 这也解决了“无效证书”浏览器警告问题。
详细说明Radmilla Mustafa的回答:
Nginx使用“主机”标头进行server_name匹配。 它不使用TLS SNI。 这意味着对于SSL服务器,nginx必须能够接受SSL连接,这归结为证书/密钥。 证书/密钥可以是任何的,例如自签名的。
见文件
因此,解决scheme是:
server { server_name _; listen 80 default_server; listen 443 ssl default_server; ssl_certificate <path to cert>; ssl_certificate_key <path to key>; return 404; # or whatever }