Take the 2-minute tour ×
Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

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?

share|improve this question

1 Answer 1

up vote 1 down vote accepted

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.

share|improve this answer
1  
wiki.nginx.org/IfIsEvil –  Alexander Azarov Feb 20 '12 at 12:01
1  
Yeah, I undersrtand this. Still, I have examples, where if is a lot better and solved tons of problems in my opinion. Also, I did not recommend the problematic, quoted types of use :) –  petermolnar Feb 20 '12 at 13:46
1  
And still, testing $uri inside location is really evil -- this is exactly what location is for. –  Alexander Azarov Feb 20 '12 at 17:38
1  
Could you please give me a detailed explanation why exactly? I still see this is the most elegant way to solve this exact problem. –  petermolnar Feb 21 '12 at 8:27
1  
location directive is used to define a configuration based on URI: wiki.nginx.org/HttpCoreModule#location It is optimized for this task (i.e. static lookups are much faster than regexp matches), it has reasonable precedence rules. Basically I'm just re-iterating what documenation says. –  Alexander Azarov Feb 21 '12 at 8:40

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.