Requests and static files
Serve static files safely
Map request URIs to files with root, alias, index, and tryfiles while avoiding accidental exposure.
8 minute lesson
Serving files is about one mapping: how does a request URI become a filesystem path? Nginx gives you two directives for it, and they behave differently.
root appends the full request URI to a directory. alias replaces the matching location prefix with another path.
server {
listen 80;
server_name static.example.com;
root /var/www/site/public;
location / {
index index.html;
try_files $uri $uri/ =404;
}
location /downloads/ {
alias /srv/files/;
}
}
With root, a request for /css/site.css reads /var/www/site/public/css/site.css — directory plus the whole URI. With alias, a request for /downloads/report.pdf reads /srv/files/report.pdf — the /downloads/ prefix is swapped for /srv/files/. If you had used root /srv/files/ there, Nginx would look for /srv/files/downloads/report.pdf, which is almost never what you meant.
try_files $uri $uri/ =404 checks the exact file first, then a directory of that name (which triggers index), then gives up with a 404. It’s the standard pattern for static sites because it never invents paths: the request either maps to a real file or fails cleanly.
Directory listing stays off unless you have a deliberate reason to enable it. autoindex defaults to off, so a directory without an index file returns 403 instead of exposing its contents. Leave it that way.
Keep private files out of the root
The root directory is a public boundary. Anything inside it can be requested by URL, so keep secrets, dotfiles, and build artifacts outside. Publish a public/ directory and keep .env, source code, and backups one level up where no URI can reach them.
Verify the behavior with three requests:
curl -I http://static.example.com/index.html # 200
curl -I http://static.example.com/missing.css # 404
curl -I http://static.example.com/.env # 404 - lives outside the root
The failure mode to watch for is a misplaced trailing slash with alias. location /downloads/ paired with alias /srv/files (no trailing slash) produces paths like /srv/filesreport.pdf, and every request 404s. Keep both the location prefix and the alias path ending in /, then re-test with a known file.
Serve a small public directory containing index.html and one asset. Verify a missing path returns 404 and a sibling private file cannot be requested.
Lesson completed