问:NGINX - 通过“map”动态映射多个不同的域名作为“server_name”

问:NGINX - 通过“map”动态映射多个不同的域名作为“server_name”

寻求一些建议和同行的意见 - 我目前正在尝试以某种方式配置 NGINX,以便我可以同时配置多个网站,而无需设置单独的 VHost 配置或在我的 NGINX 配置中声明具有重复配置参数的多个“server {}”条目。到目前为止,我取得了部分成功,但我担心这样做可能会造成安全问题或无意中定义范围过广。我也不确定如何正确使用“map”指令中的“默认”值。

总而言之,目前我有一个典型的 NGINX 配置,其中 2 个 VHost 配置用于一个域名(以及一个 'www.*' 子域名),位于 'nginx_root/sites-available' 中 - 一个用于 HTTP(端口 80),一个用于 HTTPS(端口 443),它们软符号链接到 'nginx_root/sites-enabled'。但如前所述 - 我想添加其他域名,但通过使用 NGINX 'map' 功能动态设置新域名,保持这些配置的数量和大小与当前相同。

我目前映射它的方法是创建一个配置文件:“nginx_root/mapped_fqdn.conf”,然后我将它包含在我的 NGINX 配置中(这样它在配置中被进一步调用/引用之前就被映射了),然后使用该映射作为“server_name”参数。如果可以将其扩展到其他配置参数并且这样做是安全的,我想以同样的方式添加新的域名。

映射的_fqdn.conf:

### Domain name mapping
    map $host $fqdn_map {
        hostnames;
        default 0;

        domain-1.com 0;
        www.domain-1.com 0;
    }

00-http.conf:

server {
    listen 80;
    listen [::]:80;
    server_name $fqdn_map;
    root /var/www/public_html;
    index index.html;
    access_log /var/log/nginx/nginx_access.log nginx_access;;

    ### HTTP to HTTPS Redirect
    return 301 https://$server_name$request_uri;
}

为了不重复,我将跳过添加 HTTPS 配置,它看起来大致相同,只是它有一些小的附加参数,以及添加的 SSL 特定的配置参数,并且没有 HTTP 配置中存在的 301 重定向。

在我看来,我可以以同样的方式添加额外的域名......

更新后的mapped_fqdn.conf示例: (我认为添加特定的子域名可能比添加通配符更安全,例如:“*.domain.com”)

### Domain name mapping
    map $host $fqdn_map {
        hostnames;
        default 0;

        domain-1.com 10;
        www.domain-1.com 11;

        domain-2.co.uk 20;
        www.domain-2.co.uk 21;
        subdomain1.domain-2.co.uk 22;
        subdomain2.domain-2.co.uk 23;

        domain-3.com 30;
        www.domain-3.com 31;
        subdomain1.domain-3.com 32;
    }

更新后的00-http.conf示例:

server {
    listen 80;
    listen [::]:80;
    server_name $fqdn_map;
    root /var/www/$fqdn_map/public_html;
    index index.html;
    access_log /var/log/nginx/$fqdn_map-nginx_access.log nginx_access;;

    ### HTTP to HTTPS Redirect
    return 301 https://$server_name$request_uri;
}

但是,在继续之前,我担心这将如何与目录一起工作,即:让我们为 HTTPS 配置加密证书 - 是否可以具体选择要使用哪些映射项?例如:$fqdn_map{10|20|30}(这样只选择没有子域名的域名)。

    ssl_client_certificate /etc/ssl/certs/$fqdn_map{10|20|30}/cloudflare_origin.pem;
    ssl_certificate /etc/letsencrypt/live/$fqdn_map{10|20|30}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$fqdn_map{10|20|30}/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/$fqdn_map{10|20|30}/chain.pem;

或者也许我以错误的方式处理这个问题,我应该分别映射 FQDN 和子域...或者可能只是从映射的子域目录到 fqdn 目录创建符号链接和连接(这虽然会导致配置更少/更干净,但会导致更多的符号链接,有点违背了“少做多得”的目的)?

答案1

如果您只是想将主机名映射到证书目录,那么您可以使用这种方法:

map $http_host $certdir {
    hostnames;

    dom1.example.com dom1;
    dom2.example.com dom2;
    .example.com dom;
}

server {
    listen 443 ssl;

    server_name something.example.com;

    ssl_certificate /path/to/certificates/$certdir/dom.crt;
    ssl_certificate_key /path/to/certificates/$certdir/dom.key;
    ...
}

此处的$certdir值为dom,因为与定义something.example.com相匹配。.example.commap

--- 第一个回答最初未提出的问题的答案 ---

也许您正在寻找这个:

server {
    listen 80 default_server;

    server_name _;

    root /var/www/$host/public_html;

    ....
}

我们在这里指定一个default_server块,它处理所有在其他地方没有匹配的虚拟主机的请求。

然后我们使用$host包含域名的变量。

如果只想对某些域使用更具体的匹配,请使用正则表达式:

server {
     listen 80;

     server_name ~ ^(domain-1.com|domain-2.com)$;

     root /var/www/$host/public_html;

     ....
}

您可以细化正则表达式。

但是,正如我在评论中所述,这将限制您如何自定义每个服务器块。您可以使用include /etc/nginx/conf.d/$host.conf在另一个文件中添加特定于域的配置。

不过,从长远来看,配置管理系统仍然是最佳选择。

相关内容