正确设置https的“默认”nginx服务器

我有几台服务器在同一台机器上运行,一些只使用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

只是提醒 :

  • 在重新加载/重新启动之前testingnginxconfiguration: 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 }