When configuring NGINX for static content with expiration headers, many developers encounter 404 errors due to improper root path handling in location blocks. The issue stems from how NGINX processes the root
directive within nested location contexts.
Your original configuration has two critical issues:
location /images {
expires 1y;
root /srv/www/static/images; # This is problematic
}
The root
directive inside location /images
changes the document root for this location, making NGINX look for files at:
/srv/www/static/images/images/screenshots/something.png
Notice the duplicate images
path? That's why you're getting 404 errors.
Here are two proper ways to configure this:
Option 1: Single Root with Location Prefix
server {
listen 80;
server_name static.*;
root /srv/www/static; # Define root once at server level
location / {
deny all;
}
location /images {
expires 1y;
log_not_found off;
# No root needed here - inherits from server
}
}
Option 2: Alias Directive for Special Cases
server {
listen 80;
server_name static.*;
location / {
root /srv/www/static;
deny all;
}
location /images/ {
expires 1y;
log_not_found off;
alias /srv/www/static/images/; # Note trailing slash
}
}
- root appends the location path to the root path
- alias replaces the location path with the alias path
- Always include trailing slashes in alias paths
- root is generally preferred for most cases
After making changes, always:
nginx -t # Test configuration
systemctl reload nginx # Apply changes
Check headers with:
curl -I http://static.example.com/images/test.jpg
For optimal static content delivery, consider adding these directives:
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 1y;
add_header Cache-Control "public, no-transform";
access_log off;
log_not_found off;
}
When setting up NGINX to serve static content with custom cache headers, many developers encounter 404 errors specifically when trying to configure separate location blocks for images. The issue typically manifests when:
- Files exist in the correct directory path
- Basic root configuration works without location blocks
- Custom location blocks return 404 errors unexpectedly
The primary issue in the original configuration comes from misunderstanding how NGINX's root
directive works within location blocks. When you specify:
location /images {
root /srv/www/static/images;
}
NGINX will actually look for files at /srv/www/static/images/images/...
because the location path gets appended to the root path.
Here are two working solutions:
Option 1: Use alias instead of root
location /images {
alias /srv/www/static/images;
expires 1y;
log_not_found off;
}
Option 2: Proper root directive structure
location /images {
root /srv/www/static;
expires 1y;
log_not_found off;
}
When working with static file serving in NGINX, keep these points in mind:
alias
replaces the matched path segmentroot
appends the matched path segment- Always verify file permissions (nginx user needs read access)
- Consider adding
try_files
for better error handling
Here's a production-tested configuration that handles static files with proper caching:
server {
listen 80;
server_name static.example.com;
location /images/ {
alias /srv/www/static/images/;
expires 1y;
access_log off;
add_header Cache-Control "public";
# Optional: Enable brotli/gzip for images if precompressed
gzip_static on;
}
location / {
root /srv/www/static;
try_files $uri =404;
}
}