Alex
Alex

Reputation: 68078

Combine multiple nginx configs into a single one

This is a config "template" I am using right now:

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

Notice the {:keywords}. These are strings that I replace with a script that is generating the nginx final config. It works fine, but I have around 300 websites and the script will generate 300 of these configs using this template, so the final nginx .conf file is quite large. Could I use a single nginx config for all sites somehow?

Upvotes: 3

Views: 1743

Answers (1)

emptyhua
emptyhua

Reputation: 6692

Here is a all in one configuration i have verified with nginx/1.18.0, but still need to generate a domain list file /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 "";
    ~^([^:]+):([^:]+):([^:]+)$ $1;
}

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

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

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

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

content of /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";

notes

  1. Nginx support using variable in ssl_certificate directive since 1.15.9, and $ssl_server_name was introdued in nginx/1.70. Because http variable $http_host will not be initialized until the https connection is established, $ssl_server_name is not replace able in this configuration.
  2. You could replace {:sharedHtmlRoot} in server block with your real path.
  3. The all in one server block is delared as a default block, if there's already a default server block in your nginx configuration, you need to overwrite the old one.

Upvotes: 4

Related Questions