The Debian and Ubuntu layout:
/etc/nginx/nginx.conf — common settings, with an include of sites at the
bottom;
/etc/nginx/sites-available/ — site files;
/etc/nginx/sites-enabled/ — links to enabled sites; nginx reads only these;
/var/log/nginx/access.log and error.log — the logs.
Enable a site
sudo ln -s /etc/nginx/sites-available/docs /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
A file in sites-available without a link in sites-enabled is invisible to
nginx. To disable a site, remove the link; the file stays.
nginx -t checks the whole config and names the file and line of an error.
reload re-reads the config without dropping connections; with an error in the
config nginx keeps the old one. systemctl reload returns at once, while the
new worker processes take connections a moment later: a curl on the same
line may still see the old state.
Logs
access.log has a line for every request, error.log says why a request
failed and what broke at start. The default access.log format is
combined:
127.0.0.1 - - [20/Oct/2026:10:03:58 +0000] "POST / HTTP/1.1" 405 166 "-"
Field by field: $remote_addr (client address), -, $remote_user,
[$time_local], "$request" (method, path, version), $status (code),
$body_bytes_sent (body size), "$http_referer", "$http_user_agent" — the
user agent "curl/8.5.0" did not fit in the example. log_format defines
your own format — in a site file outside the server block:
log_format timed '$remote_addr [$time_local] "$request" '
'$status $body_bytes_sent $request_time';
access_log /var/log/nginx/app.log timed;
$request_time is how many seconds nginx spent on the request. Files with
.1 and .2.gz next to a log are older ones that logrotate moves aside and
compresses on schedule (/etc/logrotate.d/nginx).
Proxy: path and headers
Whether there is a URI after the address in proxy_pass decides which path the
application receives:
location /api/ and proxy_pass |
Request /api/x goes out as |
http://127.0.0.1:3003 |
/api/x — path unchanged |
http://127.0.0.1:3003/ |
/x — /api/ replaced with / |
By default the application sees Host: 127.0.0.1:3003 — the address from
proxy_pass. The site name and the client address are passed in headers:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
HTTPS and the redirect from HTTP
server {
listen 443 ssl;
server_name shop.lab.test;
ssl_certificate /etc/nginx/tls/fullchain.pem;
ssl_certificate_key /etc/nginx/tls/shop.key;
root /var/www/shop;
}
server {
listen 80;
server_name shop.lab.test;
return 301 https://$host$request_uri;
}
ssl_certificate is the chain file: the site
certificate first, the intermediate after it. $request_uri is the path with
the query after ?: http://shop.lab.test/x?y=1 redirects to
https://shop.lab.test/x?y=1. Certificates and how they are checked —
openssl-tls.