3

I'm using Nginx as a caching proxy server. I have problems with caching responses using both X-Accel-Expires and Cache-Control headers.

My upstream returns some request body with headers to nginx:

[...]
X-Accel-Expires: 60
Cache-Control: no-cache
[...]

My intent is that nginx will cache response for 60 seconds but clients will get only Cache-Control: no-cache header (so they will not cache response in the browser).

But nginx isnt caching that response. Nginx honour Cache-Control header and ignoring X-Accel-Expires header. I thought that X-Accel-Expires is "stronger" that Cache-Control but it is not.

Is there any way to change that?

I know that I can use:

proxy_ignore_headers Cache-Control;

But I cant do that because I don't have X-Accel-Expires headers in every response from upstream server.


To sum up when I return thoose headers from upstream:

X-Accel-Expires: 60
Cache-Control: no-cache

I want to cache response in nginx cache for 60s but return to clients Cache-Control: no-cache.

But when I return this:

Cache-Control: max-age=90

(without X-Accel-Expires header) I want to cache response in nginx cache for 60s and return to clients Cache-Control: max-age=90 header.

Is this possible?

1

Then,

  • Modify the upstream to send X-Accel-Expires header everytime or add it with add_header directive (using for instance $http_cache_control in a if statement).
  • Ignore Cache-Control header for caching everytime.
  • Use an upstream block.
map $upstream_http_cache_control $cache_control_value {
    "~^max-age=(?<duration>\d+)$" "$duration";
}

server {

   listen 127.0.0.1:80;

    upstream nodes {
        server foo;
    }

    location / {

        if ($upstream_http_x_accel_expires = '') {
            add_header "X-Accel-Expires" $cache_control_value;
        }

        proxy_set_header "Host" $host;
        proxy_pass http://nodes;
    }

}

server {

   server_name mydomain.com;

   listen X.X.X.X:80;

   upstream intermediate {
       server 127.0.0.1;
   }

   location / {
       proxy_set_header "Host" $host;
       proxy_pass http://intermediate;
       proxy_ignore_headers 'Cache-Control';
       proxy_cache mycache;
   }

}

For the last case refer to the first point or use proxy_cache_valid, but with this last paremeter you can't make the timeout dynamic. You need some coherent workflow at one point.

  • Thanks for answser but this isnt working. 'if' logic in this case is in action after nginx cache module decided to not to cache response. My upstream returned only: Cache-Control: 60. Nginx added X-Accel-Expires header as it should but there is no file in the cache and clients see both Cache-Control and X-Accel-Expires header in the response. So this is clear that this IF logic is placed after cache logic happens. – Tereska Nov 2 '14 at 9:21
  • @Tereska Of course, you need to set an intermediate vhost. See updated answer for clarity. But keep in mind that the best way to achieve this is to correct your workflow. – Xavier Lucas Nov 2 '14 at 11:01
  • WOW. this is clever :) One more thing: Cache-Control:max-age=60. How to put only value "60" (without maxage=) from Cache-Control to X-Accel-Expires (I'm refering to the IF statement). Without some regexp(?) I will end up with X-Accel-Expires: max-age=60 (and I think this will not work(?)) – Tereska Nov 2 '14 at 11:35
  • @Tereska Use a map statement and capture the right value with a regex. – Xavier Lucas Nov 2 '14 at 11:39
  • could you give im some example what do you mean? (it could be in pseudo code if you dont have time). thank you. – Tereska Nov 2 '14 at 11:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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