捕获所有无效子域的 nginx 服务器块

lon*_*nix 3 nginx nginx-config

我在一台主机上有多个域,nginx 管理所有这些域。每个域都有自己的 SSL 证书(我使用“webroot”插件从 certbot 获取该证书)。

我在每个配置文件的末尾都有一个服务器块,作为“包罗万象”(来自此处此处),为无效子域返回 404。

默认 nginx 配置文件default.conf

# ...other config...
include /path/to/domain1.conf;
include /path/to/domain2.conf;
# ...other config...
Run Code Online (Sandbox Code Playgroud)

domain1.conf

# redirect http to https
server {
  listen      80;
  listen      [::]:80;
  server_name domain1.com www.domain1.com
  return      301 https://$host$request_uri;
}

# redirect naked to www
server {
  listen      443 ssl http2;
  listen      [::]:443 ssl http2;
  server_name domain1.com
  include     path/to/ssl_config.conf
  return      301 https://www.$host$request_uri;
}

# serve subdomain www
server {
  listen      443 ssl http2;
  listen      [::]443 ssl http2;
  server_name www.domain1.com
  include     path/to/ssl_config.conf
  location    / { proxy_pass http://$app; }
}

# catch-all for invalid subdomains (e.g. foo.domain1.com)
server {
  listen       443 ssl http2 default_server;
  listen       [::]:443 ssl http2 default_server;
  server_name: _.domain1.com
  include      path/to/ssl_config.conf
  return       404;
}
Run Code Online (Sandbox Code Playgroud)

domain2.conf

# same as above, but uses "domain2.com" instead of "domain1.com"
Run Code Online (Sandbox Code Playgroud)

但这会导致错误:

[emerg] xxx.xxx.xxx.xxx:443 的重复默认服务器

如果我删除这些default_server指令,那么它就无法正确路由:请求foo.example1.com重定向到www.foo.example1.com,然后重定向到www.www.foo.example1.com,等等。

除了无效的子域逻辑之外,一切正常。我该如何修复它?

Iva*_*sky 5

您只需要单个默认服务器块即可捕获其他服务器块中未定义的所有其他内容。您不需要公开该块中的任何真实证书;出于安全目的,请使用虚拟自签名证书/密钥。您根本不需要server_name在该块中使用任何内容;此外,它_根本不充当通配符。你可以看到

server_name _;
Run Code Online (Sandbox Code Playgroud)

由于历史原因,有时在某些 nginx 配置中会出现这种情况,因为在 nginx 0.7.12 之前,您需要将某些内容指定为server_name,而现在不再需要了。更多信息请参考官方文档:

在包罗万象的服务器示例中"_"可以看到奇怪的名称:

server_name _;
Run Code Online (Sandbox Code Playgroud)

这个名字没有什么特别的,它只是无数与任何真实姓名不相交的无效域名之一。其他无效名称如"--"和 也"!@#"可以同样使用。

下面是一个包罗万象的块的示例:

server {
    listen       80  default_server;
    server_name  _;
    return       444;
}
Run Code Online (Sandbox Code Playgroud)

要在一行中生成一对自签名密钥/证书,您可以使用以下命令:

openssl req -nodes -new -x509 -subj "/CN=localhost" -keyout /some/path/any.key -out /some/path/any.crt
Run Code Online (Sandbox Code Playgroud)

一个好的做法是将此存根服务器块作为/etc/nginx/conf.d/default.conf/etc/nginx/sites-enabled/default文件内容,具体取决于您实际使用的虚拟主机服务风格(有关此主题的长篇讨论可以在 ServerFault 中找到

如果您使用 certbot,请不要允许它在使用此类存根服务器块的情况下自动生成重定向服务器块。由于所有具有无效请求主机名的内容都将由存根块处理,而不是像

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 default_server ssl;
    listen [::]:443 default_server ssl;
    ssl_certificate /some/path/any.crt;
    ssl_certificate_key /some/path/any.key;
    return 444; # silently drop the connection
    # or you can define some landing page here
}
Run Code Online (Sandbox Code Playgroud)

使用以下之一:

openssl req -nodes -new -x509 -subj "/CN=localhost" -keyout /some/path/any.key -out /some/path/any.crt
Run Code Online (Sandbox Code Playgroud)

要将非 www 重定向到 www,将 HTTP 重定向到 HTTPS,请为每个托管虚拟主机使用三个服务器块:

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com;
    # ssl certificate/key for 'example.com' domain here
    return 301 https://www.example.com$request_uri;
}
server {
    listen 80;
    listen [::]:80;
    server_name www.example.com;
    return 301 https://www.example.com$request_uri;
}
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name www.example.com;
    # ssl certificate/key for 'www.example.com' domain here
    # the main configuration part
    ...
}
Run Code Online (Sandbox Code Playgroud)