将多个 nginx 配置组合成一个

Combine multiple nginx configs into a single one

这是我现在正在使用的配置“模板”:

server {
  server_name {:primaryDomain};
  listen 443 ssl;
  ssl_certificate /etc/letsencrypt/live/{:primaryDomain}/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/{:primaryDomain}/privkey.pem;
  include /etc/letsencrypt/options-ssl-nginx.conf;
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
  root {:siteRoot};
  index index.php index.html;

  recursive_error_pages off;
  error_page 403 = /HTTP_ERRORS/403.html;
  error_page 404 = /HTTP_ERRORS/404.html;
  error_page 500 = /HTTP_ERRORS/500.html;
  
  location ^~ /HTTP_ERRORS/ {
    alias {:sharedHtmlRoot}/;
    internal;
  }  
  
  location / {
    try_files $uri $uri/ /index.php?$query_string;
  }

  location /manage {
    root {:siteRoot}/manage;  
    try_files $uri $uri/ /manage/index.php?$query_string;
  }

  location ~* \.php$ {
    fastcgi_pass unix:/run/php/php{:phpVer}-fpm-{:user}.sock;
    include         fastcgi_params;
    fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
    fastcgi_param   SCRIPT_NAME        $fastcgi_script_name;
  }

  location /assets/ {
    alias /public/assets/;
  }     
}

server {
  server_name {:primaryDomain} www.{:primaryDomain};
  listen 80;
  return 301 https://{:primaryDomain}$request_uri;
}

server {
  server_name www.{:primaryDomain};
  listen 443 ssl;
  ssl_certificate /etc/letsencrypt/live/{:primaryDomain}/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/{:primaryDomain}/privkey.pem;
  include /etc/letsencrypt/options-ssl-nginx.conf;
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;  
  return 301 https://{:primaryDomain}$request_uri;
}

注意 {:keywords}。这些是我用生成 nginx 最终配置的脚本替换的字符串。 它工作正常,但我有大约 300 个网站,脚本将使用此模板生成其中的 300 个配置,因此最终的 nginx .conf 文件非常大。 我能以某种方式对所有站点使用单个 nginx 配置吗?

这是一个 all in one 配置,我已经用 nginx/1.18.0 验证过,但仍然需要生成域列表文件 /etc/nginx/mydomains

/etc/nginx/sites-enabled/default

map $http_host $vhost_config {
    hostnames;
    default "";
    include /etc/nginx/mydomains;
}

map $vhost_config $vhost_root {
    default "";
    ~^([^:]+):([^:]+):([^:]+)$ ;
}

map $vhost_config $php_version {
    default "";
    ~^([^:]+):([^:]+):([^:]+)$ ;
}

map $vhost_config $php_user {
    default "";
    ~^([^:]+):([^:]+):([^:]+)$ ;
}

map $ssl_server_name $my_cert_name {
    default "";
    ~^(www\.)?(.+)$ ;
}

server {
    listen 80 default_server;
    listen 443 ssl default_server;

    ssl_certificate /etc/letsencrypt/live/$my_cert_name/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$my_cert_name/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    server_name ~^(?<www>(www\.)?)(?<domain>.+)$;

    recursive_error_pages off;
    error_page 403 = /HTTP_ERRORS/403.html;
    error_page 404 = /HTTP_ERRORS/404.html;
    error_page 500 = /HTTP_ERRORS/500.html;

    location ^~ /HTTP_ERRORS/ {
        alias {:sharedHtmlRoot}/;
        internal;
    }

    # redirect www.abc.com to abc.com
    if ($www != '') {
        return 301 https://$domain$request_uri;
    }

    # redirect http to https
    if ($scheme = 'http') {
        return 301 https://$domain$request_uri;
    }

    # if domain not exist in mydomains, return 404
    if ($vhost_root = '') {
        return 404;
    }

    root $vhost_root;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location /manage {
        root $vhost_root/manage;
        try_files $uri $uri/ /manage/index.php?$query_string;
    }

    location ~* \.php$ {
        fastcgi_pass unix:/run/php/php$php_version-fpm-$php_user.sock;
        include         fastcgi_params;
        fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
        fastcgi_param   SCRIPT_NAME        $fastcgi_script_name;
    }

    location /assets/ {
        alias /public/assets/;
    }
}

/etc/nginx/mydomains

的内容
# domain.name "<site root>:<php version>:<php user>";
abc.com "/var/www/html/abc:7.4:user1";
efg.com "/var/www/html/efg:7.0:user2";

笔记

  1. 1.15.9 以来,Nginx 支持在 ssl_certificate 指令中使用变量,并且 $ssl_server_name 是在 nginx/1.70 中引入的。因为在建立 https 连接之前,http 变量 $http_host 不会被初始化,所以 $ssl_server_name 在此配置中不可替换。
  2. 您可以将 server 块中的 {:sharedHtmlRoot} 替换为您的真实路径。
  3. all in one server 块被声明为默认块,如果您的 nginx 配置中已经有一个默认服务器块,您需要覆盖旧的。