Nginx – Cache control, set private cache per user

We can cache a public resource without problem but when caching a private resource. There are some notices we must take in account:

  1. According to Nginx document:

The following response headers flag a response as uncacheable unless they are ignored:
Cache-Control containing "no-cache", "no-store", "private", or a "max-age" with a non-numeric or 0 value
Expires with a time in the past
X-Accel-Expires: 0
It means that if in response we have at least one of these Headers, the response will not be cached.

  1. Nginx will distinguish the cache by using cache_key, so $request_uri does not enough for distinguish user also so if we need to cache per user, we need to provide some per user information to Nginx cache_key like $cookie_xxx

Here is an complete example of Nginx config for per user caching (with uwsgi):

uwsgi_cache_path /tmp/nginx_cache_my_app levels=1:2 keys_zone=my_app:10m;
limit_req_zone $binary_remote_addr zone=restrict_my_app:10m rate=2r/s;
server {
listen 80;
server_name my_app.com;
rewrite ^ https://$server_name$request_uri? permanent;
server {
listen 443 ssl;
server_name my_app.com;

access_log /var/log/nginx/my_app.log main;
error_log /var/log/nginx/my_app.log error;

ssl_certificate /etc/ssl/nginx/my_app.com.crt;
ssl_certificate_key /etc/ssl/nginx/my_app.com.key;

root /var/www/my_app;

Does not cache the index.html

location /index.html {
if_modified_since off;
etag off;
expires -1; # This will set Cache-Control: no-cache automatically

uwsgi_cache my_app;
uwsgi_cache_key $request_uri$cookie_my_cookie_name;
uwsgi_no_cache $http_x_cache_bypass;
uwsgi_cache_use_stale timeout;
uwsgi_cache_use_stale error;
uwsgi_connect_timeout 5;
uwsgi_read_timeout 15;
uwsgi_send_timeout 15;
uwsgi_ignore_client_abort on;

Does not cache /auth and set a rate limit for this URL

location /auth {
limit_req zone=restrict_api_intranet_trotro burst=4 nodelay;
add_header Vary Cookie; # For IE8, if not IE8 will take cache on another user
uwsgi_cache_valid 0; # => disable cache
uwsgi_pass uwsgi_fastrouter; # Fast router pass
include uwsgi_params;

location /api {
# Very important, because without this, Nginx will not cache the response
uwsgi_ignore_headers "Set-Cookie";
add_header Vary Cookie; # For IE8, if not IE8 will take cache on another user
uwsgi_cache_valid 10s;
include uwsgi_params;
uwsgi_pass uwsgi_fastrouter;
Explain: 2 important keys:

  1. uwsgi_cache_key $request_uri$cookie_my_cookie_name;

This will distinguish cache by URI and value of my_cookie_name, so for each user (each cookie) and each URI we have a specific cache

  1. uwsgi_ignore_headers “Set-Cookie”;

Tell Nginx that event we have Set-Cookie is response, we will cache the response

comments powered by Disqus