Skip to content

The config grammar

Scope: the small grammar every nginx config is written in — directives, blocks, contexts — and the inheritance rules that decide which setting wins.

Directives and blocks

A directive is one instruction ending in a semicolon:

root /var/www/example;
index index.html;

A block is a directive whose value is a set of braces containing more directives:

server {
    listen 127.0.0.1:8080;
    server_name localhost;
    root /home/you/nginx-lab/www/main;
}

Blocks nest, and where a directive sits is its context. The contexts you will actually use:

Context Lives in Holds
main the file's top level user, worker_processes, pid, error_log
events main how workers take connections (worker_connections)
http main everything about serving: global logs, mime types, and the servers
server http one virtual host: a listen port plus a name
location server (or location) what happens for one slice of the URL space
upstream http a named pool of backends for proxying

Comments start with #. Whitespace is free. A missing semicolon is the most common typo in the wild, and nginx -t names the line when you make it.

Inheritance

Settings flow downward: a directive set in http is the default for every server, and a server's settings are the default for its locations — until a closer context sets its own, which replaces (never merges with) the outer one for that directive.

Two consequences:

  • Put genuinely global things in http once: access_log, include mime.types, the limit_req_zone. The lab config's whole top half is exactly that.
  • Array-style directives replace wholesale. The classic surprise is proxy_set_header: if a location sets any proxy_set_header, it inherits none of the ones from the enclosing server. This bites real configs; chapter 7 sets the full header block inside the location for this reason.

Seeing the config nginx sees

Files include other files; symlinks decide what's live. When you're unsure what nginx is actually working from, ask it to print the fully expanded configuration:

$ nginx -T
# configuration file /home/you/nginx-lab/nginx.conf:
# Lab nginx for "nginx for Mere Mortals".
...
user root;
pid /home/you/nginx-lab/prefix/nginx.pid;

nginx -T is nginx -t (test) plus the dump — every include inlined, in order. It is the ground truth, and the first thing to reach for when a running nginx behaves as if your edit doesn't exist: usually it doesn't, because the file you edited isn't the file being loaded (an unlinked site, an unsaved buffer, a second config tree).

Check: take any config on a machine you administer and predict, for one location, which root and which access_log apply — then confirm with nginx -T. Being wrong about this is normal the first time; inheritance is the whole lesson.