5

My task is to implement microcaching strategy using nginx, that is, cache responses of some POST endpoints for a few seconds.

In http section of the nginx.conf I have the following:

proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;

Then I have location in server:

    location /my-url/ {
      root dir;
      client_max_body_size 50k;
      proxy_cache cache;
      proxy_cache_valid 10s;
      proxy_cache_methods POST;
      proxy_cache_key "$request_uri|$request_body";
      proxy_ignore_headers Vary;

      add_header X-Cached $upstream_cache_status;

      proxy_pass http://my-upstream;
    }

The application located at my-upstream outputs Cache-Control: max-age=10 which, if I understand correctly, should make the responses cacheable.

But when I make repetitive requests using curl in short time (less than 10 seconds)

curl -v --data "a=b&c=d" https://my-host/my-url/1573

all of them reach the backend (according to backend logs). Also, X-Cached is always MISS.

Request and response follow:

> POST /my-url/1573 HTTP/1.1
> Host: my-host
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Length: 113
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 113 out of 113 bytes
< HTTP/1.1 200 OK
< Server: nginx
< Date: Tue, 08 May 2018 07:16:10 GMT
< Content-Type: text/html;charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Keep-Alive: timeout=60
< Vary: Accept-Encoding
< X-XSS-Protection: 1
< X-Content-Type-Options: nosniff
< Strict-Transport-Security: max-age=31536000
< Cache-Control: max-age=10
< Content-Language: en-US
< X-Cached: MISS

So the caching does not work.

  1. What am I doing wrong here?
  2. Is there any logging facility in nginx that would allow to see why it chooses not to cache a response?
Jignesh Joisar
  • 13,720
  • 5
  • 57
  • 57
Roman Puchkovskiy
  • 11,415
  • 5
  • 36
  • 72

2 Answers2

6

It turned out that the following directive (which was defined globally) prevented caching from working:

proxy_buffering off;

When I override it under location config with proxy_buffering on;, caching starts working.

So, to make caching work with POST requests, we have to do the following:

  1. Output Cache-Control: public, max-age=10 header on the server
  2. Add proxy_cache_path config and location config in nginx (examples are given in the question text)
  3. Make sure that proxy_buffering is on for the location on which we want to have caching enabled.
Roman Puchkovskiy
  • 11,415
  • 5
  • 36
  • 72
  • 1
    This answer, together with the question, not only solves the original problem, but serves as a concise tutorial for setting up nginx POST caching. You saved me from a considerable amount of trial and error. Well asked and well answered. – Wayne Conrad Sep 25 '19 at 19:06
0

To elaborate on @Roman Puchkovskiy's answer above - my origin server was returning the following headers:

Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache

I configured my server to return this instead:

Cache-Control: max-age=3600, public

And now Nginx behaves as expected ✅

I first tried adding this directive to my nginx.conf:

...
location /blah {
  ...
  proxy_ignore_headers Cache-Control;
}

But it looks like that directive doesn't work the way I thought it would.

Note that I wasn't required to add proxy_buffering on to my nginx.conf so it seems I wasn't affected by that issue.

Adam
  • 2,616
  • 33
  • 29