Configuration Basics
A complete server block for serving static files, plus the core listen, server_name and location directives.
A complete server block
Here is a full, working server block that serves a static site — the kind of config you'd write for a plain HTML/CSS/JS site with no backend application:
# /etc/nginx/sites-available/mysite.conf
server {
listen 80;
server_name example.com www.example.com;
root /var/www/mysite/public;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
location /static/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
access_log /var/log/nginx/mysite.access.log;
error_log /var/log/nginx/mysite.error.log;
}
The core directives
listen — which port (and optionally which IP address) this server block accepts connections on.
listen 80; # any IP, port 80
listen 127.0.0.1:8080; # only localhost, port 8080
listen 443 ssl; # HTTPS
server_name — which Host header(s) this block responds to. Nginx can host many domains on one IP address; when a request comes in, Nginx picks the server block whose server_name best matches the request's Host header.
server_name example.com www.example.com;
server_name *.example.com; # wildcard subdomain
server_name ""; # matches requests with no/unrecognized Host header
root — the filesystem directory that URL paths are resolved against. A request for /about.html on the config above resolves to /var/www/mysite/public/about.html.
index — the file to serve when a request maps to a directory rather than a specific file. index index.html index.htm; means: for a request to /, try index.html first, then index.htm.
The location block
A location block matches an incoming request's URL path and decides how to handle it. Nginx supports several match types:
location / {
# matches everything not matched more specifically elsewhere (prefix match)
try_files $uri $uri/ =404;
}
location /api/ {
# prefix match — matches any path starting with /api/
proxy_pass http://backend;
}
location = /health {
# exact match — only /health, nothing else
return 200 "OK";
}
location ~ \.php$ {
# regex match (case-sensitive) — any path ending in .php
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~* \.(jpg|jpeg|png|gif)$ {
# regex match (case-insensitive)
expires 30d;
}
try_files $uri $uri/ =404; is the standard pattern for a static site: try the exact file ($uri), then try it as a directory ($uri/), and if neither exists, return a 404 instead of leaking a filesystem error.
Common mistakes
- Forgetting the trailing slash consistency between
locationandproxy_passtargets — it changes whether the matched prefix is stripped from the forwarded path (a classic, hard-to-spot bug). - Using a regex
locationfor everything out of habit — prefix matches are simpler, faster, and sufficient for most routing needs. - Not setting
expires/Cache-Controlon static assets — browsers re-request unchanged files on every visit instead of caching them. - Editing the config and forgetting
nginx -t && systemctl reload nginx— changes don't take effect until reloaded.