Nginx – How to force to cache requests that have “Cache-Control: no-cache” in nginx when using a reverse proxy and it responds with 404

cachenginxreverse-proxy

The upstream server is sending a 404 with a header of Cache-Control: no-cache.

Due to this, nginx is not caching the request. How can I force it to cache the request?


This caching is only required on the upstream repsponses with a 404 status code.

It can keep the original header and pass this on to the client, but I don't want it sending a 'fresh' request to the page.

I also don't want to remove the header entirely as some of the requests would have a appropriate 'cache control' header set to expire in for example 24h. Hence I can't use proxy_ignore_headers.

Best Answer

I've been lucky in that I can do this based on the response code (404) and by intercepting the error:

#user www-data;
#worker_processes 4;
#pid /run/nginx.pid;
#
#events {
#   worker_connections 768;
#   # multi_accept on;
#}
user  www-data;
worker_processes  4;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    #access_log  /dev/null;
    #error_log /dev/null;

    sendfile        off;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;
  proxy_cache_path  /tmp/nginx  levels=1:2    keys_zone=STATIC:10m inactive=24h  max_size=1g;

  server {
      listen 80 default_server;
      listen [::]:80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
  }

  server {
      listen 443 default_server ssl;
        listen [::]:443 default_server ssl;

      server_name  localhost;

      ssl on;
      ssl_certificate /opt/bitnami/nginxssl/nginxssl.crt;
      ssl_certificate_key /opt/bitnami/nginxssl/selfbuild.key;
    recursive_error_pages on;

      location / {
          proxy_pass https://localhost:9443/;
          proxy_set_header Host            $host;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

          proxy_cache            STATIC;
      # Let the Set-Cookie header through.

          add_header X-Proxy-Cache $upstream_cache_status;
          proxy_cache_valid 404      60m;
      error_page 404 /404.html;
      proxy_intercept_errors on;

      }

      location /404.html {

          proxy_pass https://localhost:9443/404.html;

      proxy_hide_header Set-Cookie;
          proxy_hide_header Cache-Control;
          proxy_hide_header Expires;
          proxy_hide_header Pragma;
          proxy_hide_header X-Accel-Expires;
      proxy_ignore_headers "Set-Cookie" "Cache-Control" "Expires" "X-Accel-Expires";

          proxy_set_header Host            $host;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

          proxy_cache            STATIC;

          add_header X-Proxy-Cache $upstream_cache_status;
          proxy_cache_valid 404      60m;

      }
  }
}