Q:

How to DRY nginx configuration

I have nginx config for the current and legacy application where the only difference between the two blocks is DNS-specific entries and root path. How can I put specific parts of the config in a variable or something and then call that variable in both server config blocks?
server {
  listen                0.0.0.0:443 ssl;
  server_name           mysite.com;
  ssl_certificate       /etc/ssl/server.crt;
  ssl_certificate_key   /etc/ssl/server.key;
  ssl_protocols         SSLv3 TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers           RC4:HIGH:!aNULL:!MD5;
  ssl_session_cache     shared:SSL:15m;
  ssl_session_timeout   15m;

  root /home/deployer/apps/myapp/current/public;

  if ($request_method !~ ^(GET|HEAD|POST)$ ) {
       return 444;
  }

  if ($http_user_agent ~* LWP::Simple|BBBike|wget) {
      return 403;
  }

  if ($http_user_agent ~* (spider|AcoiRobot|msnbot|scrapbot|catall|wget) ) {
      return 403;
  }

  location ^~ /assets/ {
    gzip_static on;
    gzip_vary on;
    expires max;
    add_header Cache-Control public;
  }
  location ~ \.(gif|png|jpe?g|JPE?G|GIF|PNG {
      valid_referers none blocked mysite.com *.mysite.com;
      if ($invalid_referer) {
        return   403;
      }
  }
  location /evil/ {
     valid_referers none blocked mysite.com *.mysite.com;
     if ($invalid_referer) {
        return   403;
    }
  }

  try_files $uri/index.html $uri @puma;
  location @puma {
    proxy_set_header  X-Real-IP       $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto https;
    proxy_set_header  Host $http_host;
    proxy_redirect    off;
    proxy_pass        http://puma;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 4G;
  keepalive_timeout 10;
}

How can I DRY up everything below the root line?

A:

Time has proven Alexey Ten's comment about using include to be the right way to go.  
We use this in production:  
File structure in /etc/nginx
nginx.conf
sites-enabled/app_config
modules/shared_serve
modules/shared_ssl_settings

In /etc/nginx/sites-enabled/app_config:
upstream puma {
  server unix:/tmp/puma.socket fail_timeout=1;
}

server {
  server_name example.com;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

  include modules/shared_ssl_settings;

  include modules/shared_serve;
}

In /etc/nginx/modules/shared_ssl_settings:
listen                443 ssl;
listen                [::]:443;
ssl                   on;
ssl_protocols         TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers On;

ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

ssl_session_timeout  1d;
ssl_session_cache    shared:SSL:30m;
ssl_stapling         on;
ssl_stapling_verify  on;
add_header           Strict-Transport-Security max-age=15768000;

In /etc/nginx/modules/shared_serve:
location ~ \.(php|aspx|asp|myadmin)$ { return 444; log_not_found off; }

root /home/deployer/apps/example_app/current/public;

try_files $uri/index.html $uri @puma;

location @puma {
  proxy_set_header  X-Real-IP       $remote_addr;
  proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header  X-Forwarded-Proto https;
  proxy_set_header  Host $http_host;
  proxy_redirect    off;
  proxy_pass        http://puma;
}

error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;

The only gotcha is that your deploy script has to ensure the file structure in /etc/nginx. Naturally, you can name your module directory anything else. You might even keep the includable files right in /etc/nginx without a subdirectory.

