← All 57 books nginx starters, one directive per page Get the full edition · £10
One directive per page

nginx starters, one directive per page

Twenty-seven steps for developers who've shipped sites but never owned the nginx layer: the master and its workers, the nginx.conf tree of directives and contexts, nginx -t and graceful reloads, signals, worker_processes and worker_connections, include, listen, server_name and the Host header, root, the location search order, try_files, mime.types, sendfile, gzip, keep-alive, expires, error_page, proxy_pass and its trailing slash, proxy_set_header, retries, upstream groups, the access log's time fields, error_log levels, client_max_body_size, and TLS with listen 443 ssl and SNI, one directive per page.


Steve Hodgkiss 7 steps

A diagram, the classic trap, and one thing to go try this week. That's a page.

nginx starters, one directive per page

Twenty-seven steps for developers who've shipped sites but never owned the nginx layer: the master and its workers, the nginx.conf tree of directives and contexts, nginx -t and graceful reloads, signals, worker_processes and worker_connections, include, listen, server_name and the Host header, root, the location search order, try_files, mime.types, sendfile, gzip, keep-alive, expires, error_page, proxy_pass and its trailing slash, proxy_set_header, retries, upstream groups, the access log's time fields, error_log levels, client_max_body_size, and TLS with listen 443 ssl and SNI, one directive per page.


Set in Space Grotesk, Inter and JetBrains Mono (SIL Open Font License).

nginx behaviour checked against the official nginx documentation (nginx.org/en/docs, mainline), fetched and read during this build: Beginner's Guide; Controlling nginx; Command-line parameters; Core functionality (worker_processes, worker_connections, include, error_log); Events; How nginx processes a request; Configuring HTTPS servers; and the http core, proxy, upstream, gzip, log and headers module references. Concepts and directives are named as the documentation names them. Teaching conventions (one directive a day) are named as conventions. This book quotes no verbatim passages and is an independent guide not affiliated with or endorsed by F5, Inc. NGINX is a trademark of F5, Inc.

General information only. Not professional advice; verify against your own nginx version and the current documentation.

Your purchase is for personal use only. You do not have redistribution rights: please do not share, resell, or republish this book or its pages.

© 2026 Steve Hodgkiss. All rights reserved. Personal use only; no redistribution rights.

Edition 1.0 · stevehodgkiss.net

Contents

Contents


Part 1 · The model4
One master, many workers5
nginx.conf, the tree6
nginx -t, then reload7
Part 2 · Serving8
listen 809
location, the search order10
Part 3 · Proxying
proxy_pass http://app:300011
Part 4 · Limits and TLS
client_max_body_size 1m12
Part 1 of 4
Master, workers, config
1

The model

What nginx is: one master reading config, workers doing the serving, the directive-and-context tree of nginx.conf, test-then-reload, the signals, and the worker sizing knobs.


In this part
  1. 01One master, many workers
  2. 02nginx.conf, the tree
  3. 03nginx -t, then reload

nginx has one master process and several worker processes. The main purpose of the master process is to read and evaluate configuration, and maintain worker processes. Worker processes do actual processing of requests. nginx employs an event-based model and OS-dependent mechanisms to efficiently distribute requests among worker processes. Per the nginx official Beginner's Guide.

nginx starters · No. 01
The model

One master, many workers

The master reads config. Workers do the work.

one master, several workersnginx masterreads nginx.confworker 1event-basedworker 2event-basedworker 3event-basedthe master evaluates config; the workers serve requests

Let's say someone says "the site's behind nginx" and you nod. Worth knowing what's actually running.

There's one master process. It reads and evaluates the configuration and maintains worker processes. The workers do the actual request processing, with an event-based model, one worker handling many connections at once. You don't spawn workers per request. You edit nginx.conf, the master notices, workers get the new config.

The master reads. The workers serve.

TRY THIS WEEK

Run ps -ax | grep nginx on any nginx box this week. One master, several workers. That's the shape.

The way nginx and its modules work is determined in the configuration file. By default the configuration file is named nginx.conf and placed in the directory /usr/local/nginx/conf, /etc/nginx, or /usr/local/etc/nginx. A simple directive consists of the name and parameters separated by spaces and ends with a semicolon. A block directive ends with braces instead. Per the nginx official Beginner's Guide.

nginx starters · No. 02
The model

nginx.conf, the tree

Directives, semicolons, and blocks

the configuration treenginx.confsimple directive + ;block directive + { }mainevents {http {server {location / {contexts nest:main holds http,http holds server,server holds location# the rest of a line# is a comment

Let's say you open /etc/nginx/nginx.conf for the first time and it's just... text. It's simpler than it looks.

Everything nginx does lives in this file. A simple directive is a name and parameters, separated by spaces, ending in a semicolon. A block directive swaps the semicolon for braces, and if it can hold other directives it's called a context: events, http, server, location. The stack is main, then http, then server, then location. After a # the rest of a line is a comment.

Name, parameters, semicolon. Or braces.

TRY THIS WEEK

Open your nginx.conf this week and find the http block. Count the contexts: main, http, server, location.

nginx -t tests the configuration. The reload signal makes the master process check the syntax validity of the new configuration file and try to apply it. If this is a success, the master process starts new worker processes and sends messages to old worker processes requesting them to shut down. Otherwise it rolls back and continues with the old configuration. Per the nginx official Beginner's Guide.

nginx starters · No. 03
The model

nginx -t, then reload

Test first. Reload second.

test, then reload$ nginx -tsyntax is ok ... successfulnginx masterreload signalnew workersold workers finishif the check fails: roll back,keep the old configurationreload = syntax check, new workers, graceful goodbye to old ones

Let's say you edited nginx.conf on a live box at 5pm on a Friday. The habit that saves you is two commands.

First nginx -t: it tests the configuration without applying it. If the syntax is wrong you'll know now, not when the server won't start. Then nginx -s reload: the master checks the syntax again, and if it's valid it starts new workers and asks the old ones to shut down gracefully, finishing the requests they're serving. If the test fails, the master keeps the old configuration running.

-t is free. A broken reload isn't.

TRY THIS WEEK

This week, before your next reload: nginx -t, read the output, only then nginx -s reload.

Part 2 of 4
listen, names, files
2

Serving

Getting bytes to browsers: where a server listens, how the Host header picks the block, root's path math, the location tournament, try_files, MIME types, and sendfile.


In this part
  1. 01listen 80
  2. 02location, the search order

listen sets the address and port for IP, or the path for a UNIX-domain socket on which the server will accept requests. Both address and port, or only address or only port can be specified. The default_server parameter marks the default server for that port. Default is listen *:80. Per the nginx http core module documentation.

nginx starters · No. 04
Serving

listen 80

Where the server answers

where the server answersserver { ... }answers where listen sayslisten 443 ssl;listen 80;defaultclient80client443no server_name match? the port's default_server answersdefault is *:80; the default is a property of the port

Let's say the site answers on 443 but you're not sure where that's decided. It's the listen line.

listen sets the address and port the server accepts requests on. Address, port, or both: listen 80, listen 127.0.0.1:8080, all valid. Default is *:80. The default_server parameter marks which server block answers when nothing else matches that port, and it's a property of the port, not of the name. For HTTPS you add ssl: listen 443 ssl.

Every server block opens with listen. Read it first.

TRY THIS WEEK

Find every listen line in your config this week. Know which block is default_server for each port.

The location directive sets configuration depending on a request URI. To find a matching location, nginx first checks prefix locations and selects the longest matching prefix. Then regular expressions are checked in the order of their appearance in the configuration file; the search terminates on the first match. If no regular expression matches, the configuration of the prefix location remembered earlier is used. The = modifier defines an exact match, and ^~ skips the regular expression check. Per the nginx http core module documentation.

nginx starters · No. 05
Serving

location, the search order

Prefixes first, then regexes

the location tournamentprefixes:location /location /images/longest winsregexes:~ \.(png)$~* \.(jpg|gif)$in order, first winsskippers:location = /exactexact match, donelocation ^~ /imgslongest prefix, skip regexesno regex match? the remembered prefix block is usedlocations test the URI only, never the query string

Let's say a request matches two location blocks and you can't tell which one wins.

nginx remembers the longest matching prefix, then checks regexes in config order, first match wins and stops. No regex match means the remembered prefix is used. Two modifiers bend it: = is an exact match, ^~ on the longest prefix skips the regex check. Only the URI is tested, never the query string.

Longest prefix, then regexes in order. That's the tournament.

TRY THIS WEEK

Take one URL you serve and walk it through the order by hand this week. Then check you were right.

The proxy_pass directive sets the protocol and address of a proxied server. If proxy_pass is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive. If proxy_pass is specified without a URI, the request URI is passed in the same form as sent by the client. In these cases when location is specified using a regular expression, proxy_pass should be specified without a URI. Per the nginx proxy module documentation.

nginx starters · No. 06
Proxying

proxy_pass http://app:3000

The trailing slash rewrites

the trailing slash rewriteslocation /api/request: GET /api/usersproxy_pass http://app:3000/;with a URI/api/users -> /usersproxy_pass http://app:3000;no URI/api/users -> /api/userswith a URI, the part matching the location is replacedin a regex location: proxy_pass must have no URI (the docs say so)

Let's say the app receives /api/users but expected /users. One character decides it.

proxy_pass sends the location's requests onward. With a URI, the part matching the location is replaced: location /api/ plus proxy_pass http://app:3000/ turns /api/users into /users. Without a URI, the request goes as sent. In a regex location the docs are firm: no URI.

The trailing slash is a rewrite. Treat it like one.

TRY THIS WEEK

Log what your backend actually receives this week. The path you see is the slash's fault.

client_max_body_size sets the maximum allowed size of the client request body. If the size in a request exceeds the configured value, the 413 Request Entity Too Large error is returned to the client. Setting size to 0 disables checking of client request body size. Default is 1m. Please be aware that browsers cannot correctly display this error. Per the nginx http core module documentation.

nginx starters · No. 07
Proxying

client_max_body_size 1m

The upload ceiling nobody set

the upload ceiling nobody setuploadthe user's 8 MB filedefault: 1mthe request bar runs past the cap413Request Entity Too Largebrowsers cannot display itthe user sees a broken uploadset client_max_body_size where uploads land, on purpose, with a number

Let's say every upload over one megabyte fails with an error page that explains nothing. That's nginx, not the app.

client_max_body_size caps the request body, and the default is 1m. Over the cap nginx returns 413, and the docs warn that browsers cannot correctly display this error. Set it where uploads land; 0 disables the check.

Uploads break at 1m by default. Nobody set it, so you must.

TRY THIS WEEK

Check client_max_body_size everywhere uploads flow this week. Then set it on purpose, with a number.

Index

Index


client_max_body_size 1m12
listen 809
location, the search order10
nginx -t, then reload7
nginx.conf, the tree6
One master, many workers5
proxy_pass http://app:300011