Score:0

Adding location-block to cache files makes those files return 404

in flag

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.

Ivan Shatsky avatar
gr flag
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?
O'Niel avatar
in flag
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.
Ivan Shatsky avatar
gr flag
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).
O'Niel avatar
in flag
@IvanShatsky View edit. Files are not getting cached.
Ivan Shatsky avatar
gr flag
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?
O'Niel avatar
in flag
I thought the path was the actual path of file on the VPS. I removed the `Website` part and now it's working! Thanks!
Ivan Shatsky avatar
gr flag
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.
O'Niel avatar
in flag
@IvanShatsky Of course mate. Your help is appreciated.
Score:1
gr flag

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.

Score:1
us flag

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;
}
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.