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 listen socket, then the server whose server_name matches the Host header, falling back to default_server.
  • A request with no matching server_name and no default_server still hits the first server block on that port, which is rarely what you intended.
  • include is how packaged installs split configuration: extra files are pulled in from conf.d/ and sites-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
}
DirectivePath resolution
root /var/wwwAppends 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.htmlFile served when the request maps to a directory
try_files a b cServes 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 -t in 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.

Reverse proxy and TLS Caching, compression and traps

Last refreshed 2026-09-18.