Shivam
Shivam

Reputation: 2248

NGINX Browser Caching Not Working - Node JS EC2

Went through several articles but cannot figure out why the browser caching isnt working. I am using prerender.io as well as SSL:

gzip on;
gzip_min_length  500;
gzip_proxied     any;
gzip_comp_level 4;
gzip_types  text/css text/javascript text/xml text/plain text/x-component application/javascript application/json application/xml application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
gzip_vary on;
gzip_disable     "msie6";

server {
    listen 8080 default_server;
    listen [::]:8080 default_server;
    server_name <servername> www.<servername>.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2 default_server;
    server_name <servername> www.<servername>.com;

    ssl_certificate /etc/pki/tls/private/<servername>.com.chained.crt;
    ssl_certificate_key /etc/pki/tls/private/private.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers <ssl_ciphers_code>

    ssl_session_cache shared:SSL:5m;
    ssl_session_timeout 1h;
    add_header Strict-Transport-Security "max-age=15768000" always;

    root /var/app/current;

    location / {
        proxy_set_header X-Prerender-Token iKJwgCElYIfxtt9u99Zg;

        set $prerender 0;
        if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
            set $prerender 1;
        }
        if ($args ~ "_escaped_fragment_") {
            set $prerender 1;
        }
        if ($http_user_agent ~ "Prerender") {
            set $prerender 0;
        }
        if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") {
            set $prerender 0;
        }

        #resolve using Google's DNS server to force DNS resolution and prevent caching of IPs
        resolver 8.8.8.8;

        if ($prerender = 1) {
            #setting prerender as a variable forces DNS resolution since nginx caches IPs and doesnt play well with load balancing
            set $prerender "service.prerender.io";
            rewrite .* /$scheme://$host$request_uri? break;
            proxy_pass http://$prerender;
        }

        # Proxy_pass configuration
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_max_temp_file_size 0;
        proxy_pass http://0.0.0.0:3000;
        proxy_redirect off;
        proxy_read_timeout 240s;
    }

    location ~* \.(ico|css|js|gif|jpeg|jpg|png|woff|ttf|otf|svg|woff2|eot)$ {
        root /var/app/current/app/dist/client/; #if i comment this out it, my css and js files are not found...
        expires 30d;
        access_log  off;
        log_not_found off;
        add_header  Pragma "public";
        add_header  Cache-Control "public";
    }

    # Increase http2 max sizes
    http2_max_field_size 64k;
    http2_max_header_size 64k;
    client_max_body_size 4G;
    keepalive_timeout 10;
}

My assets dir is as follows:

JS: /var/app/current/app/dist/client/js

CSS: /var/app/current/app/dist/client/assets/css

Images: /var/app/current/app/dist/client/assets/graphics

Fonts: /var/app/current/app/dist/client/assets/fonts

Videos: /var/app/current/app/dist/client/assets/videos

UPDATED CONFIG:

gzip on;
gzip_min_length  500;
gzip_proxied     any;
gzip_comp_level 4;
gzip_types  text/css text/javascript text/xml text/plain text/x-component application/javascript application/json application/xml application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
gzip_vary on;
gzip_disable     "msie6";

server {
  listen 8080 default_server;
  listen [::]:8080 default_server;
  server_name <servername.com> <www.servername.com>;
  return 301 https://$server_name$request_uri;
}

server {
  listen 443 ssl http2 default_server;
  server_name <servername.com> <www.servername.com>;

  ssl_certificate /etc/pki/tls/private/<servername>.com.chained.crt;
  ssl_certificate_key /etc/pki/tls/private/private.key;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers <ciphers>;

  ssl_session_cache shared:SSL:5m;
  ssl_session_timeout 1h;
  add_header Strict-Transport-Security "max-age=15768000" always;

  root /var/app/current;

  location / {
      proxy_set_header X-Prerender-Token <token> ;

      set $prerender 0;
      if ($http_user_agent ~* "developers\.google\.com|googlebot|gigabot|yeti|yandex|ia_archiver|baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
          set $prerender 1;
      }
      if ($args ~ "_escaped_fragment_") {
          set $prerender 1;
      }
      if ($http_user_agent ~ "Prerender") {
          set $prerender 0;
      }
      if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") {
          set $prerender 0;
      }

      #resolve using Google's DNS server to force DNS resolution and prevent caching of IPs
      resolver 8.8.8.8;

      if ($prerender = 1) {
          #setting prerender as a variable forces DNS resolution since nginx caches IPs and doesnt play well with load balancing
          set $prerender "service.prerender.io";
          rewrite .* /$scheme://$host$request_uri? break;
          proxy_pass http://$prerender;
      }

      # Proxy_pass configuration
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_max_temp_file_size 0;
      proxy_pass http://0.0.0.0:3000;
      proxy_redirect off;
      proxy_read_timeout 240s;
  }

  location ~* \.(ico|css|js|gif|jpeg|jpg|png|woff|ttf|otf|svg|woff2|eot)$ {
      root /var/app/current/app/dist/client/; #if i comment this out it, my css and js files are not found...
      expires 30d;
      access_log  off;
      log_not_found off;
      add_header  Pragma "public";
      add_header  Cache-Control "public";
  }

  location /assets/graphics/ {
    proxy_ignore_headers Cache-Control;
    proxy_cache_valid any 30d;
  }

  # Increase http2 max sizes
  proxy_buffers 8 16k;
  proxy_buffer_size 32k;
  http2_max_field_size 64k;
  http2_max_header_size 64k;
  client_max_body_size 4G;
  keepalive_timeout 10;
}

Upvotes: 3

Views: 1947

Answers (1)

Taterhead
Taterhead

Reputation: 5951

In your NGINX configuration, you set the cache expiration to 30 days for your images with the line:

expires 30d;

However looking at your images coming from your server, the max-age of the images is set to 0 which is causing your browser to re-pull the images on a refresh (below image was after a refresh):

enter image description here

I suspect that NGINX is acting as a proxy to an origin server that is part of your solution. This origin server is setting the max-age to 0 in the cache-control header and NGINX is respecting that setting.

Per the NGINX caching guide:

By default, NGINX respects the Cache-Control headers from origin servers. It does not cache responses with Cache-Control set to Private, No-Cache, or No-Store or with Set-Cookie in the response header. NGINX only caches GET and HEAD client requests.

To override the cache-control set at the origin server and set the max-age to 30d, use the NGINX proxy_ignore_headers and proxy_cache_valid directive like so:

...
location /assets/graphics/ {

    proxy_ignore_headers Cache-Control;
    proxy_cache_valid any 30d;
    ...
}
...

The code in my solution is taken directly from the NGINX caching guide and modified to your configuration.

Or determine how to change the cache control headers at the origin server.

UPDATE

After you updated your NGINX config, your images in the /assets/graphics/ directory are pulled from local browser memory and have expiration of 30 days (2595200) as seen below. Yesterday, they were all being pulled from your server and not being cached. This solution solves your problem. For the rest of the assets that you want cached, you need to further change your config to also cache these according to your requirements.

enter image description here

enter image description here

Upvotes: 5

Related Questions