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


70

我有几台服务器在同一台计算机上运行,​​有些服务器仅使用http,有些服务器同时使用http和https。在主配置文件中包含的单独文件中定义了几个服务器块。

我为http设置了一个“默认”服务器,该服务器将为通用的“维护页面”提供服务,以与其他配置文件中的任何其他server_name不匹配的请求。http默认服务器按预期工作,它使用server_name“ _”,并且它首先出现在包含列表中(因为我观察到,如果在服务器之间有重复的server_names,则使用出现的第一个)。这很好。

我希望有相同的服务器块(仅将“ listen 80 default_server”切换为“ listen 443 default_server”,而不是服务页面“ return 444”),但事实并非如此。取而代之的是,尽管其他服务器块对传入的请求具有更合适的server_name,但新的默认https服务器似乎实际上正在捕获所有传入的https连接并导致它们失败。删除新的默认https服务器将导致恢复半正确的行为:带有https的网站将全部正确加载;但没有https的网站将全部路由到包含文件中的第一个https服务器(根据文档,如果未显示“ default_server”,则出现的第一个服务器块将为“ default”)。

所以我的问题是,在Nginx中为SSL连接定义“默认服务器”的正确方法是什么?为什么当我显式设置“ default_server”时,它会变得贪婪并获取所有连接,而当我隐式地让nginx决定“ default server”时,它会像我期望的那样工作(将错误的服务器设置为default,其他真实服务器行为正确)?

这是我的“默认服务器”。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;
    }
}

你们中有人看到这里有什么问题吗?

ssl  https  nginx 

Answers:


27

您在“默认” https块中没有定义任何ssl_certificate或ssl_certificate_key。尽管您没有或想要此默认方案的真实密钥,但仍需要配置一个密钥,否则nginx将具有您描述的不良行为。

创建一个具有*的通用名称的自签名证书,并将其插入您的配置中,该证书将根据需要开始工作。

在此设置下,“默认”行为是浏览器将收到警告,表明证书不可信任,如果用户将证书添加为例外,则nginx将删除该连接,并且他们将看到其浏览器的默认设置“无法连接”错误消息。


1
我已经尝试过了,但是它仍然不起作用:所有对IP的ssl请求都转到了我的其他ssl主机。还有什么我可以尝试的吗?
MichaelHärtl2015年

22

我设法用nginx在单个IP上配置了一个共享的专用主机。默认HTTP和HTTPS为未知域传入提供404服务。

1-创建一个默认区域

由于nginx以ascii顺序加载虚拟主机,因此您应该在中创建00-default文件/符号链接/etc/nginx/sites-enabled

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-创建自签名证书,测试并重新加载

您需要在中创建一个自签名证书/etc/nginx/ssl/nginx.crt

创建默认的自签名证书:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

只是提醒:

  • 在重新加载/重启之前测试nginx配置: nginx -t
  • 重新享受: sudo service nginx reload

希望能帮助到你。


2
无法解决浏览器访问不安全站点的警告。
gdbj

4
无法解决,因为包罗万象必须与任何域匹配。没有SSL可以通配所有域。想象一下,如果您在服务器上欺骗google.fr地址,则可以将服务器认证为google.fr。这将是一个严重的安全问题:(
如果

是的,我想这很有道理。不幸的是,在Chrome中,在看到404页面之前,您会收到一个可怕的警告,这比让服务器简单地拒绝流量更糟糕。使其看起来好像服务器配置错误。
gdbj

非常感谢你。这对我有用,除了我必须添加default_server监听443,并用添加IPv6地址[::]:80和[::]:443 default_server
chmike

16

我们基本上希望不惜一切代价避免将配置文件中的第一个服务器定义用作SSL连接的万能服务器。我们都知道它可以做到这一点(与http相对并使用default_server config效果很好)。

对于SSL来说,这尚不能以声明方式实现(因此),因此我们必须使用IF对其进行编码。

该变量$host是请求行中的主机名或http标头。变量$server_name是我们现在所在的服务器块的名称。

因此,如果这两个不相等,则您为另一个主机提供了此SSL服务器块,因此应将其阻止。

该代码不包含对服务器IP地址的特定引用,因此可以轻松地将其重用于其他服务器配置,而无需进行修改。

例:

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;
    }

    ...

你能解释一下listen [::]:443 ssl http2;吗?我在查找文档方面遇到困难。
安德鲁·布朗

我想我找到了,只需要知道要搜索什么。IPV4和IPV6指令。
安德鲁·布朗

7

要详细说明Radmilla Mustafa的答案,请执行以下操作:

Nginx使用“主机”头进行server_name匹配。它不使用TLS SNI。这意味着对于SSL服务器,nginx必须能够接受SSL连接,这归结为具有证书/密钥。证书/密钥可以是任何值,例如,自签名。

参阅文件

因此,解决方案是:

server {
    server_name _;
    listen 80 default_server;
    listen 443 ssl default_server;

    ## To also support IPv6, uncomment this block
    # listen [::]:80 default_server;
    # listen [::]:443 ssl default_server;

    ssl_certificate <path to cert>;
    ssl_certificate_key <path to key>;
    return 404; # or whatever
}

我认为这应该是公认的答案。非常感谢。
汇总

2

对于那些像我这样失去头发的人(今天花了整整一天的时间)。我几乎尝试了所有事情,最终使它正常工作的是这条愚蠢的行:

ssl_session_tickets off;

Ifnot的答案为基础,我的工作示例是:

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name _;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    ssl_session_tickets off;

    return 404;
}

我不知道为什么这样做是必要的,我由此得出的唯一原则是,当我们不给他想要的东西时,nginx的行为会很奇怪。


1
你是一个传奇。
Nizar金发

1

如果要绝对确定,则对在HTTPS上不应答的主机和应该在HTTPS上应答的主机使用单独的IP地址。这也解决了“无效证书”浏览器警告问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.