Server blocks and static files
How nginx chooses a virtual host, how root and alias resolve a path, and how to reload a config safely.
How nginx reads its config
Configuration is a tree. http holds global settings, each server block is a virtual host, and location blocks decide what happens per URL path.
events {}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
server {
listen 80;
server_name example.com www.example.com;
location / {
root /var/www/site;
index index.html;
}
}
server {
listen 80 default_server; # catch-all for an unmatched Host header
server_name _;
return 444; # close the connection without a response
}
}- For each request nginx picks the
listensocket, then theserverwhoseserver_namematches theHostheader, falling back todefault_server. - A request with no matching
server_nameand nodefault_serverstill hits the first server block on that port, which is rarely what you intended. includeis how packaged installs split configuration: extra files are pulled in fromconf.d/andsites-enabled/.
Serving static files
location /assets/ {
root /var/www/site; # -> /var/www/site/assets/logo.png
}
location /downloads/ {
alias /srv/files/; # -> /srv/files/thing.pdf
}
location / {
root /var/www/app/dist;
index index.html;
try_files $uri $uri/ /index.html; # single-page-app fallback
}| Directive | Path resolution |
|---|---|
root /var/www | Appends the full request URI: /img/a.png becomes /var/www/img/a.png |
alias /srv/files/ | Replaces the matched location prefix with the alias path |
index index.html | File served when the request maps to a directory |
try_files a b c | Serves the first path that exists; the last entry is the fallback |
With alias the trailing slashes matter. location /downloads/ with alias /srv/files/; maps /downloads/a.pdf to /srv/files/a.pdf. Omit either slash and you get a path such as /srv/filesa.pdf.
Test and reload
sudo nginx -t # parse the config, report the first error
sudo nginx -T | less # dump the fully expanded config
sudo nginx -s reload # graceful: new workers, old ones drain
sudo systemctl reload nginx # the same thing under systemd- A reload keeps existing connections alive on the old workers while new ones serve the new configuration.
- Commercial builds add Lua and dynamic upstreams; the free build needs a reload for most changes.
- Run
nginx -tin CI before deploying a config. A broken file stops a reload, and a restart would take the site down.
💡
nginx -t validates syntax and file paths, not intent. A config can pass and still serve the wrong site because of server-block ordering, so always request the real hostname afterwards.FAQ
Why does my new site answer for the wrong hostname?
Another server block on the same port is catching it. Look for a
default_server or an earlier block whose server_name matches, and dump the effective config with nginx -T.A file that exists returns 404?
The resolved filesystem path is wrong. Remember that
root appends the whole URI, then check the file exists and is readable by the nginx user.Related
Reverse proxy and TLS Caching, compression and traps
Last refreshed 2026-09-18.