我有几台服务器在同一台计算机上运行,​​有些服务器仅使用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;
    }
}


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

#1 楼

我设法用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


希望对您有所帮助。

评论


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

– gdbj
17年5月8日在16:38

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

–如果不是
17年5月9日14:22



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

– gdbj
17年5月9日在14:43

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

–chmike
19年4月17日在12:45



openssl命令首先需要mkdir / etc / nginx / ssl

– Wal
19年11月14日在3:07

#2 楼

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

使用Common创建自签名证书*的名称,然后将其插入您的配置中,它将开始按需要工作。

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

评论


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

– MichaelHärtl
15年8月18日在11:17

#3 楼

我们基本上希望不惜一切代价避免将配置文件中的第一个服务器定义用作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;
    }

    ...


评论


你能解释一下[::]:443 SSL http2的内容吗?有吗我在查找文档方面遇到困难。

–安德鲁·布朗(Andrew Brown)
16年8月9日在15:31

我想我找到了,只需要知道要搜索什么。 IPV4和IPV6指令。

–安德鲁·布朗(Andrew Brown)
16年8月9日在15:39

#4 楼

要详细说明Radmilla Mustafa的答案:

Nginx使用'Host'头进行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
}


评论


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

–aggregate116​​6877
18年4月15日在23:46

简单,干净的配置,完美运行。谢谢。

–mahfuz
19年11月15日在9:39



#5 楼

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

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表现得很奇怪。

评论


你是一个传奇。

– Nizar金发
19年2月11日在17:03

默认值为5分钟,我想一点耐心也可以完成这项工作:-)

–拉马特
20/12/18在15:45

#6 楼

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

#7 楼

如果仅要确保不返回任何数据,则可以使用以下不带证书的代码段:
map "" $empty {
        default "";
}

server {
        listen 80 default_server;
        listen 443 ssl http2 default_server;
        listen [::]:80 default_server;
        listen [::]:443 ssl http2 default_server;

        server_name _;

        ssl_ciphers aNULL;
        ssl_certificate data:$empty;
        ssl_certificate_key data:$empty;

        return 444;
}