Nginx – how to get server inheritance / adding caching headers to various reverse proxied sites

cachenginxreverse-proxy

I have about 5 sites running on different ports via reverse proxy and accessible under different sub domains. Some of these sites are setting the expires (/ cache-control max age header) by themselves and don't require this to be managed, however some do not.

For the ones that I do not, I want to specify expires for static content (as per https://github.com/h5bp/server-configs/blob/master/nginx.conf), however I cannot find a way to do this without duplicating this logic in every server. For a single server I know I can do it like this:

 server {
listen 80;

server_name sub.domain.com;

location \ {
    proxy_pass  http://localhost:1234/;
}

# cache.appcache, your document html and data
location ~* \.(?:manifest|appcache|html|xml|json)$ {
  proxy_pass    http://localhost:1234/;
  expires -1;
  access_log logs/static.log;
}

# Feed
location ~* \.(?:rss|atom)$ {
  proxy_pass    http://localhost:1234/;
  expires 1h;
  add_header Cache-Control "public";
}

# Favicon
location ~* \.ico$ {
  proxy_pass    http://localhost:1234/;
  expires 1w;
  access_log off;
  add_header Cache-Control "public";
}

# Media: images, video, audio, HTC, WebFonts
location ~* \.(?:jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|eot|mp4|ogg|ogv|webm)$ {
  proxy_pass    http://localhost:1234/;
  expires 1M;
  access_log off;
  add_header Cache-Control "public";
}

# CSS and Javascript
location ~* \.(?:css|js)$ {
  proxy_pass    http://localhost:1234/;
  expires 1Y;
  access_log off;
  add_header Cache-Control "public";
}
}

This sucks because:

  • the proxy_pass is duplicated for each location block
  • which also means I can't stick this in an external file and include it for any site that requires it.

If I have 2 sites that require this, I seem to have no choice but to duplicate the whole thing changing the proxy_pass for each location.

Is there a way to achieve 'write once use many' for the expires header (and proxy_pass) logic?

Best Answer

nginx can do inclusion, with include path-to-file; markup.

You can also use if instead of location this case, so I'd try something like this:

server {
    listen 80;
    server_name sub.domain.com;

    location / {
        if ( $uri ~* \.(?:manifest|appcache|html|xml|json)$ ) {
            expires -1;
            access_log logs/static.log;
        }

        if ( $uri ~* \.(?:rss|atom|ico|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|eot|mp4|ogg|ogv|webm|css|js) ) {
            add_header Cache-Control "public";
        }

        if ( $uri ~* \.(?:ico|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|eot|mp4|ogg|ogv|webm|css|js) ) {
            access_log off;
        }

        if ( $uri ~* \.(?:rss|atom) ) {
            expires 1h;
        }

        if ( $uri ~* \.(?:ico) ) {
            expires 1w;
        }

        if ( $uri ~* \.(?:jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|eot|mp4|ogg|ogv|webm) ) {
            expires 1M;
        }

        if ( $uri ~* \.(?:css|js) ) {
            expires 1Y;
        }

        try_files @proxy;
    }

    location @proxy {
        proxy_pass  http://localhost:1234/;
    }
}

I'm not able to test it right now, but with slight modifications this should work.