26

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?

Stefano
  • 751
  • 1
  • 12
  • 23

4 Answers4

6

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

DukeLion
  • 3,239
  • 1
  • 17
  • 19
  • I did not know about `map` - or at least I had never noticed and thought I could use it like this... let me ponder a little more about this and see if I have additional questions/comments! – Stefano May 16 '12 at 11:06
3

Is there a way to "call" a named location directly?!

There is one more way at least:

location /somelocation {
    error_page 418 = @named_location;
    return 418;
}
MingalevME
  • 131
  • 2
2

Some directives can be applied for both "server" and "location" contexts, making it DRY:

# The variables below are evaluated on each request,
# allowing to DRY configs of locations.
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $remote_addr;

location /special {
    proxy_send_timeout 10m;
    proxy_read_timeout 10m;
    proxy_pass http://pool;
}

location / {
    proxy_pass http://pool;
}
  • This is the simplest (and IMO the most clear and understandable) way to dry up directives. Besides server and location, some are valid at http level. – Tom Wilson May 14 '20 at 23:45
0

Is there a way to "call" a named location directly?! ==> it is very simple

try_files /dev/null @test ;