5

I see indications that this should work, so I'm hoping I'm missing something simple.

We have two nginx "servers", a proxy_pass cache in front and an SSI server behind it. If I go directly to the SSI server with an If-Modified-Since header in the request, it will return a 304-Not Modified response just fine, which is what we want. But I cannot get the proxy_pass cache server to return a 304-Not Modified for anything.

Should I be able to get the proxy_pass to return a 304-Not Modified? Does anyone else have it working with a config you could share? Or can you spot the problem in my config?

# this is the cache in front
server {
    listen 8096;    
    server_name _;
    proxy_buffering on;

    location /assets {
        proxy_pass http://localhost:8095;
        proxy_cache   my-cache;
        proxy_cache_valid  200s;
        if_modified_since before;
    }       
}

server {
    listen 8095;
    server_name _;
    root /var/www/;
    location / { deny all; }

    location /assets {}
        ssi on; # on or off doesn't make a difference to the front-end cache behavior
        if_modified_since before;   
    }
}

# here's the base config, fwiw:
proxy_buffering         on;
proxy_cache_valid       any 10m;
proxy_cache_path        /var/cache/nginx levels=1:2 keys_zone=my-cache:8m max_size=3000m inactive=24h;
proxy_temp_path         /var/cache/nginx/tmp;
proxy_buffer_size       4k;
proxy_buffers           100 8k;

Thanks.

Kevin G.
  • 209
  • 3
  • 12
  • 3
    With `proxy_cache`enabled, the request will not be proxied to the upstream server when the cache is hit. However, in order for your upstream server to return a 304, you'll want to send the if_modified_since header along with the request. Try out `proxy_set_header If-Modified-Since $http_if_modified_since`. – Andrew Ty. Apr 18 '13 at 17:28
  • It's actually the *downstream* server I wanted to return a 304. But your comment got me heading in the right direction--I found nginx had cached an Expires header from a previous test that was off into next week. So yes, it works with my config, thanks! – Kevin G. Apr 18 '13 at 18:28

3 Answers3

3

The problem is that nginx won't pass if-modified-since from the client through to the upstream server when caching is in effect (I believe it will depend on the presence of a proxy_cache setting). Nginx strips the if-modified-since header based on my investigation [1].

The solution is add proxy_set_header If-Modified-Since $http_if_modified_since to the front-end [2]. Fortunately, nginx doesn't try to be too smart here ... it faithfully replicates the header in the request to upstream, which is what we want.

The default Nginx behaviour makes sense if we're just caching static files, but if it's a more complex decision on the application server deciding whether to re-generate content, we need to pass it through!

  1. In case anyone wants to look into this, I discovered this is happening by adding $http_if_modified_since to the nginx access log format, on the front-end server as well as the upsteam server. For a given request, the front-end server logged the if-modified-since header that had been sent by the client, but the same request was logged with an empty if-modified-since header until I applied the proxy_set_header fix.

  2. As mentioned in Andrew Ty's comment on the question here.

mahemoff
  • 197
  • 11
1

Yes it's possible, and yes this config works fine. Turns out nginx was caching an Expires header set to next week from my testing. Never Mind :-/

Kevin G.
  • 209
  • 3
  • 12
0

The solution is to add proxy_cache_revalidate on. NGINX does not by default includes the If-Modified-Since and other conditional request headers in the request to the upstream server if caching is enabled. It requires this directive to get instructed to make conditional request to the upstream server when a resource expires.

Resources: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_revalidate

Mohsin Sethi
  • 101
  • 1