try_files doesn't use variables from regex and map

I'm trying to conditionally serve .webp images to supported clients. The images are stored like image.jpg and image.jpg.webp in the same folder.

I can't get try_files to do what I think it should to. When I use $1$webp_suffix as the location it fails and also does not try the second location.

In nginx.conf I set $webp_suffix like so:

http {
    map $http_accept $webp_suffix {
        default "";
        "~*webp"    ".webp";
    }
    include /opt/local/etc/nginx/vhosts/*;
}

But when I try to use the suffix in my virtual host I get an error 404.

server {
  
    listen 443 ssl;
    server_name my.example.com;

    # allow /data/ and /data/343/ as public URL
    location ~ ^/data/[0-9/]*(.*)$ {
        expires 365d;
        add_header Cache-Control "public, no-transform";
        # Serve webp images when available and supported
        location ~ ^/data/[0-9/]*(.+\.(png|jpg))$ {
            add_header Vary Accept;
            alias /local/path/httpdocs/data/;
            try_files $1$webp_suffix $1 =404;
        }
        alias /Users/r/Sites/cms/httpdocs/data;
        try_files /$1 =404;
    }
}

Everything works when I remove $1$webp_suffix, so the paths and such seem correct.


The problem is $1. It gets overwritten each time Nginx evaluates a regular expression. The expression $1$webp_suffix causes Nginx to evaluate the regular expression in the map statement, which simultaneously causes $1 to become an empty string.

Use a named capture in the location statements.

For example:

location ~ ^/data/[0-9/]*(?<filename>.*)$ {
    expires 365d;
    add_header Cache-Control "public, no-transform";
    # Serve webp images when available and supported
    location ~ \.(png|jpg)$ {
        add_header Vary Accept;
        root /local/path/httpdocs/data/;
        try_files /$filename$webp_suffix /$filename =404;
    }
    root /Users/r/Sites/cms/httpdocs/data;
    try_files /$filename =404;
}

Also, you should be using root instead of alias.