worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
# Map to determine the preferred image format
map $http_accept $image_suffix {
default "";
"~*image/avif" ".avif";
"~*image/webp" ".webp";
}
server {
listen 80;
location /public/images/ {
root /usr/share/nginx/html;
# Extract the base name without extension
set $base_uri $uri;
if ($uri ~* ^(.+)\.(jpeg|jpg|png)$) {
set $base_uri $1;
}
add_header X-debug-image $base_uri$image_suffix;
add_header X-debug $uri;
add_header Vary Accept;
# Try serving the preferred format or fallback to the original
try_files $base_uri$image_suffix $uri =404;
}
}
}
# pwd
/usr/share/nginx/html
# ls -l public/images
bkw2p3rvoe.avif
bkw2p3rvoe.jpeg
bkw2p3rvoe.webp
When I request my image http://localhost:8181/public/images/bkw2p3rvoe.jpeg
in the browser, it returns the jpeg
, but it should return the .avif
:
accept:
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7```
content-type: image/jpeg
vary: Accept
x-debug: /public/images/bkw2p3rvoe.jpeg
x-debug-image: /public/images/bkw2p3rvoe.avif
You cannot use if
in a location
like that. There used to be a page explaining this, but it's disappeared.
You could use a regular expression location instead.
For example:
location /public/images/ {
root /usr/share/nginx/html;
location ~* ^(?<base_uri>.+)\.(jpeg|jpg|png)$ {
add_header X-debug-image $base_uri$image_suffix;
add_header X-debug $uri;
add_header Vary Accept;
try_files $base_uri$image_suffix $uri =404;
}
}
Use a named capture, as numeric captures are reset whenever Nginx evaluates another regular expression. Because your map contains a regular expression and is evaluated after the location (where $image_suffix
is first used), $1
will be empty.
All three add_header
statements must appear within the same block, and need to be inside the regular expression location to have access to the capture.