0

I want to cache some static files using Nginx. But I somehow can't get it to work.

This is my nginx.conf:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
    #multi_accept on;
}


http {

    #GZIP
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_min_length 256;
    gzip_types application/javascript application/json application/ld+json application/xml font/eot font/otf font/ttf text/css text/javascript text/plain text/xml;

    # SERVERS
    server {
            listen      80;

        server_name example.com;
        if ($http_host ~* ^www\.(.*)$ )
        {
            return 301 https://$1$request_uri;
        }

        return 301 https://$http_host$request_uri;
    }
    server {
        listen 443 ssl;

        if ($http_host ~* ^www\.(.*)$ )
        {
            return 301 $scheme://$1$request_uri;
        }


        #SSL
        ssl_certificate /root/.acme.sh/example.com/fullchain.cer;
        ssl_certificate_key /root/.acme.sh/example.com/example.com.key;

        server_name example.com;

        # Pass all traffic to my webapplication
        location / {
            proxy_set_header Host $host;
            proxy_pass http://localhost:8080;
        }

        #Browser caching
        location ~* \.(js|css)$ {
            expires 180d;
            add_header Pragma "public";
            add_header Cache-Control "public";
        }
        location ~* \.(jpg|jpeg|png|webp|woff|woff2|ttf)$ {
            expires 365d;
            add_header Pragma "public";
            add_header Cache-Control "public";
        }

    }
}

The problem relies in the part "Browser caching". When enabling this block of code my site loads, but all the css-files, javascript-files and images return a 404. It's like those files are ignoring my location /.

I was able to solve this issue by copy/pasting

proxy_set_header Host $host;
proxy_pass http://localhost:8080;

in all my location-blocks, but that is not really elegant, and actually made my site feel a lot slower...

I also tried to move the two location-blocks for the browser caching in the block location \ so the latter would act as 'parent'. But that did not chance the behavior of images etc. returning 404.

How would I configure the caching of static files in Nginx?

Edit: I added the following to my http-block:

  map $uri $cache_control {
                ~/Website/assets/media/images    "public, no-transform";
        }
        map $uri $expire {
            ~/Website/assets/media/images   365d;
        }

Added the following to my server-block:

 expires $expire;
                add_header Cache-Control $cache_control;

Nothing is getting cached.

O'Niel
  • 105
  • 1
  • 9
  • What is your backend web app? What makes you unable to serve static files with the nginx without calling the backend like Tero Kilkanen suggest? – Ivan Shatsky Feb 07 '22 at 19:42
  • My back-end web-app is a Rust-application. And the URL the resources/files are found, is not the same as the actual location on the server. I rewrite my access and resource-paths in the web-routes. – O'Niel Feb 07 '22 at 21:05
  • Ok, if you can't serve your static assets using nginx only and should proxy all the requests to the backend, check [this](https://stackoverflow.com/a/64287782/7121513) answer. I think this is exactly what you are asking for (needs minimal adaptation). – Ivan Shatsky Feb 07 '22 at 21:36
  • @IvanShatsky View edit. Files are not getting cached. – O'Niel Feb 08 '22 at 21:21
  • 1
    Add `default off;` line to the `map $uri $expire { ... }` block. What is that `/Website` prefix? Is it really a part of the URI and not the domain name? Check if the required response headers are present with the browser DevTools or curl. Are you sure the backend app doesn't add any of those itself? – Ivan Shatsky Feb 08 '22 at 21:28
  • I thought the path was the actual path of file on the VPS. I removed the `Website` part and now it's working! Thanks! – O'Niel Feb 08 '22 at 22:07
  • 1
    Since you already started a bounty, won't you mind if I wrote it as an answer? :) I will use slightly different `map` blocks to answer your original question where JS/CSS and image files should receive different `Expires` header values. – Ivan Shatsky Feb 08 '22 at 22:29
  • @IvanShatsky Of course mate. Your help is appreciated. – O'Niel Feb 08 '22 at 23:39

2 Answers2

1

This doesn't actually answer your question, but shows a preferred way of serving static assets with nginx.

Since you seem to be running the web application on the same host, I recommend that you serve the static files directly using nginx.

root /path/to/webroot;

location ~* \.(js|jss)$ {
    expires 180d;
    add_header Pragma "public";
    add_header Cache-Control "public;

    try_files $uri =404;
}

location ~* \.(jpg|jpeg|png|webp|woff|woff2|ttf)$ {
    expires 365d;
    add_header Pragma "public";
    add_header Cache-Control "public";

    try_files $uri =404;
}

This one still has duplicate definitions for caching. You can eliminate some of the duplication by specifying directives in separate file and using include to include the file in your configuration.

You would enter the following to proxy_header.conf file:

add_header Pragma "public";
add_header Cache-Control "public";

And in your config:

location ~* ... {
    include /path/to/webroot;
    expires 365d;
}
Tero Kilkanen
  • 36,796
  • 3
  • 41
  • 63
1

If you can't serve your static assets directly from the filesystem via nginx like @TeroKilkanen suggests, you can use a technique similar to shown in this answer:

map $uri $expire {
    ~\.(?:j|cs)s$                      180d;
    ~\.(?:jpe?g|png|webp|woff2?|ttf)$  365d;
    default                            off;
}
map $uri $cache_control {
    ~\.(?:js|css|jpe?g|png|webp|woff2?|ttf)$  public;
}
server {
    ...
    expires $expire;
    add_header Pragma $cache_control;
    add_header Cache-Control $cache_control;
    ...
}

If your request URI won't match the regex, $cache_control variable will have an empty value and nginx won't add Pragma and Cache-Control header to its response at all.

Ivan Shatsky
  • 2,726
  • 2
  • 7
  • 19