Write a DRY Modular Nginx Conf with Named Locations – How to Guide

configurationnginx

I'm using nginx mostly as a reverse cachining proxy in front of several gunicon/mod_wsgi applications and of course to server static files.

I find that quickly my nginx confs become impossible to maintain; the issue is that I have a few patterns that are similar (or even identical) but I can't manage to make it clean.

One of the biggest issues I have is that I would love to use named locations as a way to group a set of confs, eg.

location @django_modwsgi {
    include proxy.conf;
    proxy_pass  http://127.0.0.1:8080;        
}

location @django_gunicorn {
    include proxy.conf; # this could also be included directly in the server {} block?
    proxy_pass  http://gunicorn_builder;
}

NB.
The issue is not having both gunicorn and wsgi.
That's just an example. Another one is:

location @namedlocation_1 {
     some cache settings;
     some cache_key settings;
     ignore some headers;
     expires;
     proxy_pass
}

location @namedlocation_2 {
     other cache settings;
     other cache_key settings;
     ignore some headers;
     expires;
     proxy_pass
}

but to call a named location the only way I found is :

location /somelocation {
    try_files $uri @named_location;
}

This already does not feel right, I do not want nginx to go look for static files, I want it to go directly to the named location! Is there a way to "call" a named location directly?!

Another way I thought I could go for dry is a lot of include

location /somelocation {
    include django_unicorn.conf;
}

But is this a good way to do it? It sounds ok for very generic settings (eg. proxy ones), but it is not very readable to have to go open different files to get the full conf.

Also, in some cases I can group a few locations with a regexp, but I like doing so ONLY when they are logically related not just to be able to put common settings in the same block.

The Question

Is there an "official" best practice to write good, DRY nginx configurations?

I would love to find a pattern like:

location / {
    common confs
    try_files $uri @name_location
}

** but how do I write specific cases for different locations? **

Could I simply add several locations with the uncommon part of the conf and the common one in the @named_location?

location /1/ {
    some cache expire settings;
    NOTHING ELSE;
}

location /2/ {
    some other cache expire settings;
    NOTHING ELSE;
}

location / {
    common settings
    try_files
}

location @named_location {
    other common settings for this named location only
    proxy_pass
}

When I have different url pointing to the same resource can I simply do a rewrite?

location /1/ {
    rewrite  ^  /3/  last;
}

location /2/ {
    rewrite ^   /4/  last; 
}

location / {
    common settings
    try_files
}

location @named_location {
    other common settings for this named location only
    proxy_pass
}

or should those be all grouped into the one location?

location / {
    rewrite ^/1/$  /3/  last;
    rewrite ^/2/$   /4/  last; 

    common settings
    try_files
}

location @named_location {
    other common settings for this named location only
    proxy_pass
}

Related

I could not find much in the mailing list, even less so in the wiki.

Please note this is /not/ the same as question NGinx Best Practices – that's a very generic question.

This other one is more relevant: How do I DRY up this Nginx configuration?

Best Answer

I've solved similar problem using nginx map feature.

First create a domain name to backend map:

map $http_host $backend {
  myhost1.tld 192.168.1.100;
  myhost2.tld 192.168.1.101;
  default     upstream_pool1;
}

then use map in location

location / {
  common settings
  proxy_pass $backend; 
}

You can use any other variable instead of $http_host See this manual: http://nginx.org/en/docs/http/ngx_http_map_module.html