DRY virtual web server configurations

2019-08-15 20:13发布

问题:

I'm using nginx 1.10.3 for a couple of virtual web servers. Most of them have the same configuration which seems to be simple (redirect non-www to www and redirect http to https) but still I end up with over 100 lines of code for each configuration. Is there a way to DRY this? e.g. not repeat the logging path every time but just one time?

It is not the biggest problem in the world but I'd like to have this cleaned up and don't know how.

Here is the config I use for each virtual server:

    # Virtual Host configuration for www.company.com
    #
    server {
        listen 80;
        server_name www.company.com;

        access_log /var/log/nginx/www.company.com-access.log;
        error_log /var/log/nginx/www.company.com-error.log;

        root /var/www/www.company.com/current;
        index  index.html index.htm;

        # Let's Encrypt Challenge
        location ~ /.well-known {
          allow all;
          root /var/www/letsencrypt;
        }

        location / {
          rewrite ^/(.*)$ https://www.company.com/$1 permanent;
          rewrite ^/$ https://www.company.com/ permanent;
        }
    }

    server {
        listen 80;
        server_name company.com;

        access_log /var/log/nginx/www.company.com-access.log;
        error_log /var/log/nginx/www.company.com-error.log;

        root /var/www/www.company.com/current;
        index  index.html index.htm;

        # Let's Encrypt Challenge
        location ~ /.well-known {
          allow all;
          root /var/www/letsencrypt;
        }

        location / {
          rewrite ^/(.*)$ https://company.com/$1 permanent;
          rewrite ^/$ https://company.com/ permanent;
        }
    }

    server {
        listen 443 ssl http2;
        server_name company.com;

        access_log /var/log/nginx/www.company.com-access.log;
        error_log /var/log/nginx/www.company.com-error.log;

        # Letsencrypt SSL certificate
        ssl_certificate     /etc/letsencrypt/live/www.company.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.company.com/privkey.pem;

        # Connection credentials caching
        ssl_session_cache shared:SSL:20m;
        ssl_session_timeout 180m;

        # Strict Transport Security
        # => Tell the client to remember that this is a https site
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

        root /var/www/www.company.com/current;
        index  index.html index.htm;

        location / {
          rewrite ^/(.*)$ https://www.company.com/$1 permanent;
          rewrite ^/$ https://www.company.com/ permanent;
        }
    }

    server {
        listen 443 ssl http2;
        server_name www.company.com;

        access_log /var/log/nginx/www.company.com-access.log;
        error_log /var/log/nginx/www.company.com-error.log;

        # Letsencrypt SSL certificate
        ssl_certificate     /etc/letsencrypt/live/www.company.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.company.com/privkey.pem;

        # Connection credentials caching
        ssl_session_cache shared:SSL:20m;
        ssl_session_timeout 180m;

        # Strict Transport Security
        # => Tell the client to remember that this is a https site
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

        root /var/www/www.company.com/current;
        index  index.html index.htm;

        location / {
          expires 7d;
          add_header Cache-Control public;

          try_files $uri $uri/ =404;
        }
    }

回答1:

The NGINX FAQ documents that you can't use variables in config.

Q: Is there a proper way to use nginx variables to make sections of the configuration shorter, using them as macros for making parts of configuration work as templates?

A: Variables should not be used as template macros. Variables are evaluated in the run-time during the processing of each request, so they are rather costly compared to plain static configuration. Using variables to store static strings is also a bad idea. Instead, a macro expansion and "include" directives should be used to generate configs more easily and it can be done with the external tools, e.g. sed + make or any other common template mechanism.

So that means you need to use a template generator like conf.d or even bash script to automate generating these config. Using bash would mean you need to escape every single $ as \$. Here is a sample approach using bash

site.template

   # Virtual Host configuration for www.${SITE}
    #
    server {
        listen 80;
        server_name www.${SITE};

        access_log /var/log/nginx/www.${SITE}-access.log;
        error_log /var/log/nginx/www.${SITE}-error.log;

        root /var/www/www.${SITE}/current;
        index  index.html index.htm;

        # Let's Encrypt Challenge
        location ~ /.well-known {
          allow all;
          root /var/www/letsencrypt;
        }

        location / {
          rewrite ^/(.*)\$ https://www.${SITE}/\$1 permanent;
          rewrite ^/\$ https://www.${SITE}/ permanent;
        }
    }

    server {
        listen 80;
        server_name company.com;

        access_log /var/log/nginx/www.${SITE}-access.log;
        error_log /var/log/nginx/www.${SITE}-error.log;

        root /var/www/www.${SITE}/current;
        index  index.html index.htm;

        # Let's Encrypt Challenge
        location ~ /.well-known {
          allow all;
          root /var/www/letsencrypt;
        }

        location / {
          rewrite ^/(.*)\$ https://${SITE}/\$1 permanent;
          rewrite ^/\$ https://${SITE}/ permanent;
        }
    }

site.sh

#!/bin/bash

generate_site_config() {
   echo generating config for $1 in $1.conf
   IN=site.template
   OUT=$1.conf
   SITE=$1 eval "cat <<EOF
   $(cat $IN)
EOF" > $OUT
}

generate_site_config $1

Then generate the config like below

$ sh site.sh tarunlalwani.com
generating config for tarunlalwani.com in tarunlalwani.com.conf

The generate config will look like below

  # Virtual Host configuration for www.tarunlalwani.com
#
server {
    listen 80;
    server_name www.tarunlalwani.com;

    access_log /var/log/nginx/www.tarunlalwani.com-access.log;
    error_log /var/log/nginx/www.tarunlalwani.com-error.log;

    root /var/www/www.tarunlalwani.com/current;
    index  index.html index.htm;

    # Let's Encrypt Challenge
    location ~ /.well-known {
      allow all;
      root /var/www/letsencrypt;
    }

    location / {
      rewrite ^/(.*)$ https://www.tarunlalwani.com/$1 permanent;
      rewrite ^/$ https://www.tarunlalwani.com/ permanent;
    }
}

server {
    listen 80;
    server_name company.com;

    access_log /var/log/nginx/www.tarunlalwani.com-access.log;
    error_log /var/log/nginx/www.tarunlalwani.com-error.log;

    root /var/www/www.tarunlalwani.com/current;
    index  index.html index.htm;

    # Let's Encrypt Challenge
    location ~ /.well-known {
      allow all;
      root /var/www/letsencrypt;
    }

    location / {
      rewrite ^/(.*)$ https://tarunlalwani.com/$1 permanent;
      rewrite ^/$ https://tarunlalwani.com/ permanent;
    }
}


标签: nginx