nginxfallback

Nginx serving static with fallback in case of 404


I'm using Nginx on Debian 12. The goal is to serve static files from two different disks and once the request is received, Nginx looks in the first directory and then in the case of 404 it proceeds to the next disk. First default location is /usr/local/www/media and the second /usr/local/www/media/extra

And yes I'm also using rewrite and secure_link as you can see.

Here's how I did it:

server {
    listen 443 ssl;
    rewrite_log on;
    log_subrequest on;
    server_name serve.example.com;
    ssl_certificate /usr/local/etc/certs/fullchain.pem;
    ssl_certificate_key /usr/local/etc/certs/key.pem;

    root /usr/local/www;

    location / {
       rewrite  /([a-zA-Z0-9_\-]*)/([0-9]*)/(.*)$ /media/$3?md5=$1&expires=$2 break;
}

    location ^~ /media {
       secure_link $arg_md5,$arg_expires;
       secure_link_md5 "$secure_link_expires$uri$remote_addr secsecretkeykey";

       if ($secure_link = "") { return 403; }
       if ($secure_link = "0") { return 410; }

       try_files $uri extra$uri =404;
       
    }
}
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name serve.example.com;
    return 301 https://$server_name$request_uri;
}

But in error.log I only see one line meaning it only looked in the primary location and did not fall back. Seems like try_files is being ignored... [error] 2810#2810: *27 open() "/usr/local/www/media/somefile.mp4" failed (2: No such file or directory)

Note that somefile.mp4 is located in /usr/local/www/media/extra


Solution

  • There are two issues here:

    1- you have a break and after that you never enter location.. and try_files. It should be last.

    location / {
       rewrite /([a-zA-Z0-9_\-]*)/([0-9]*)/(.*)$ /media/$3?md5=$1&expires=$2 last;
    }
    

    2 - try_files path is wrong.

    $uri = /media/somefile.mp4
    

    and

    extra$uri
    

    you construct

    extra/media/somefile.mp4
    

    which is here:

    /usr/local/www/extra/media/somefile.mp4
    

    so you can use map to build correct fallback path

    map $uri $extra_uri {
        ~^/media/(.*)$ /media/extra/$1;
    }
    
    server {
        listen 443 ssl;
        # ... ssl config ...
    
        root /usr/local/www;
    
        location / {
           rewrite /([a-zA-Z0-9_\-]*)/([0-9]*)/(.*)$ /media/$3?md5=$1&expires=$2 last;
        }
    
        location ^~ /media {
           secure_link $arg_md5,$arg_expires;
           secure_link_md5 "$secure_link_expires$uri$remote_addr secsecretkeykey";
    
           if ($secure_link = "") { return 403; }
           if ($secure_link = "0") { return 410; }
    
           try_files $uri $extra_uri =404;
        }
        
        # ... http→https redirect server block ...
    }
    

    Now for /media/somefile.mp4: