nginx/nginx
Configuration system
Active contributors: Sergey Kandaurov, Maxim Dounin, Aleksei Bavshin
Purpose
There are two different "configurations" in nginx:
- Build-time configuration —
auto/configureshell scripts, which decide which modules and OS features get compiled in. - Runtime configuration —
nginx.confparsed byngx_conf_file.c, which sets up modules' typed config structs.
Both are wholly hand-rolled; nginx uses neither autotools nor a third-party config DSL.
Build-time: auto/configure
graph LR
A[auto/configure] --> O[auto/options<br/>parse CLI flags]
O --> CC[auto/cc<br/>pick compiler flags]
CC --> OS[auto/os<br/>per-OS tweaks]
OS --> LIB[auto/lib<br/>probe deps]
LIB --> SRC[auto/sources<br/>which .c per subsystem]
SRC --> M[auto/modules<br/>stitch module list]
M --> MK[auto/make<br/>emit Makefile rules]
MK --> SUM[auto/summary<br/>print summary]
MK -.->|writes| OBJS[objs/Makefile<br/>objs/ngx_modules.c<br/>objs/ngx_auto_config.h]Key files in auto/:
| File | Job |
|---|---|
auto/configure |
Top-level orchestrator; sources each helper |
auto/options |
All --with-* / --without-* / --add-module=... / path flags |
auto/feature |
Reusable helper: try to compile a small C snippet to test for a feature |
auto/have |
Append #define NGX_HAVE_X 1 to ngx_auto_config.h |
auto/cc/* |
Per-compiler defaults: gcc, clang, icc, msvc, bcc, owc, sunc |
auto/lib/* |
Per-dependency probes: openssl, pcre, zlib, libxslt, libgd, geoip |
auto/os/* |
Per-OS tweaks: linux, freebsd, darwin, solaris, win32, hpux |
auto/modules |
The module table — which static modules go into the binary |
auto/sources |
Source-file lists per subsystem (CORE_DEPS, EVENT_DEPS, etc.) |
auto/make |
Generates the objs/Makefile |
auto/install |
Generates the install Makefile target |
Configure produces three artifacts under objs/:
Makefile— the actual build filengx_modules.c— a generated.clisting every static modulengx_auto_config.h—#defines for every detected platform feature
nginx -V prints back the exact configure flags the binary was built with.
Runtime: nginx.conf
The conf parser is in src/core/ngx_conf_file.c. The parser is intentionally simple: it reads tokens, matches each non-block token against the current context's directive table, and dispatches to the directive's setter function.
Directives are module data
A directive is an entry in a module's commands table, of type ngx_command_t (src/core/ngx_conf_file.h):
struct ngx_command_s {
ngx_str_t name;
ngx_uint_t type; /* context flags + arg-count flags */
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t conf; /* which config to write into */
ngx_uint_t offset; /* offset within that config */
void *post; /* extra arg for the setter */
};The type mask combines:
- Context:
NGX_MAIN_CONF,NGX_HTTP_MAIN_CONF,NGX_HTTP_SRV_CONF,NGX_HTTP_LOC_CONF, etc. - Arity:
NGX_CONF_NOARGS,NGX_CONF_TAKE1,NGX_CONF_TAKE2, ...,NGX_CONF_1MORE,NGX_CONF_ANY. - Block-ness:
NGX_CONF_BLOCKif the directive opens a{ ... }.
Common pre-built setters (defined in ngx_conf_file.c):
| Setter | Field type | Example directive |
|---|---|---|
ngx_conf_set_flag_slot |
ngx_flag_t |
daemon on; |
ngx_conf_set_str_slot |
ngx_str_t |
pid /run/nginx.pid; |
ngx_conf_set_num_slot |
ngx_int_t |
worker_rlimit_nofile 4096; |
ngx_conf_set_size_slot |
size_t |
client_max_body_size 8m; |
ngx_conf_set_msec_slot |
ngx_msec_t |
keepalive_timeout 60s; |
ngx_conf_set_sec_slot |
time_t |
proxy_cache_valid 1h; |
ngx_conf_set_enum_slot |
ngx_uint_t |
debug_points stop; |
ngx_conf_set_bitmask_slot |
ngx_uint_t |
proxy_next_upstream error timeout; |
ngx_conf_set_keyval_slot |
ngx_array_t of pairs |
proxy_set_header X Y; |
ngx_conf_set_path_slot |
ngx_path_t * |
client_body_temp_path ...; |
For directives whose semantics don't fit a slot, modules write a custom setter (e.g., ngx_set_user, ngx_set_cpu_affinity in src/core/nginx.c).
Module hooks per type
Each module type adds its own hook table under the module's ctx pointer:
| Type | Hook table type | Hooks |
|---|---|---|
NGX_CORE_MODULE |
ngx_core_module_t |
create_conf, init_conf |
NGX_EVENT_MODULE |
ngx_event_module_t |
create_conf, init_conf + the ngx_event_actions_t for backends |
NGX_HTTP_MODULE |
ngx_http_module_t |
preconfiguration, postconfiguration, create_main_conf, init_main_conf, create_srv_conf, merge_srv_conf, create_loc_conf, merge_loc_conf |
NGX_MAIL_MODULE |
ngx_mail_module_t |
create_main_conf, init_main_conf, create_srv_conf, merge_srv_conf, protocol |
NGX_STREAM_MODULE |
ngx_stream_module_t |
preconfiguration, postconfiguration, create_main_conf, init_main_conf, create_srv_conf, merge_srv_conf |
The HTTP, Mail, and Stream meta-modules (ngx_http_module, ngx_mail_module, ngx_stream_module — all NGX_CORE_MODULEs) handle the http { }, mail { }, stream { } block-opening directives. Inside those blocks, the parser switches the directive table to the corresponding type's modules.
How nginx.conf becomes C state
sequenceDiagram
participant N as ngx_init_cycle
participant Mods as ngx_modules[]
participant CP as ngx_conf_parse
participant Setter as cmd->set()
participant Conf as cycle->conf_ctx
N->>Mods: each module->create_conf
Mods->>Conf: store new struct ptrs
N->>CP: open nginx.conf
loop for each token
CP->>CP: tokenize
CP->>CP: match cmd in current ctx
CP->>Setter: call setter(cf, cmd, conf)
Setter->>Conf: write into struct via cmd->offset
end
CP-->>N: done
N->>Mods: each module->init_conf (merge defaults)
N->>Mods: each module->postconfiguration (register phase handlers)ngx_init_cycle() (src/core/ngx_cycle.c) walks ngx_modules[], invokes each module's create_conf, parses nginx.conf, then calls init_conf/merge_conf to fill in defaults from the parent context. The result is cycle->conf_ctx, a void **** indexed by module type and module index — that's why HTTP modules access their config via ngx_http_get_module_loc_conf(r, ngx_http_my_module) macros.
Variables
Inside HTTP and Stream contexts, directives can include $variable placeholders. Variables come from two sources:
- Built-in: defined by core modules at
preconfigurationtime (ngx_http_core_module'sngx_http_core_variables[]registers$uri,$args,$http_<header>,$remote_addr, etc.) - User-defined: created via
set $name value;,map $foo $bar { ... },geo $x { ... }, or by third-party modules callingngx_http_add_variable()
Variables are stored as ngx_http_variable_t keyed in a hash. At request time, looking up $x either calls a get_handler (lazy) or reads a cached value. See src/http/ngx_http_variables.c.
For directives that take "a string with variables" as an argument — proxy_pass http://$backend, log_format ..., return 301 /$args — the parser uses ngx_http_compile_complex_value() to precompile the script. At runtime, ngx_http_complex_value(r, &cv, &out_str) walks the script bytecode to produce the final string. Bytecode lives in src/http/ngx_http_script.c.
include and if and set
includeis its own module (ngx_conf_module) — it's literally one directive. Lets you split config across files.if(inngx_http_rewrite_module) is implemented by the rewrite engine, not the conf parser. The infamous "if is evil" docs page exists becauseifruns at request time inside the rewrite phase, not at config parse time.set(set $x value;) installs a setter into the rewrite-phase script that runs per-request.
Integration points
- Modules declare
commands[]and the per-type hooks. - The cycle owns the parsed config (
cycle->conf_ctx) and the listening sockets derived from it. - The master invokes
ngx_init_cycle()on startup and onSIGHUP. The cycle pattern is what makes graceful reloads work. - Build system (
auto/configure) decides which modules end up inngx_modules[]. Dynamic modules add themselves at runtime viaload_module.
Entry points for modification
Adding a directive: add an entry to the module's commands[] table, add the field to the module's config struct, write a setter (or use one of the slot helpers), update the docs in docs/xml/. Adding a directive that has variable interpolation: use ngx_http_compile_complex_value at config time, ngx_http_complex_value at request time. Adding a new directive context (a new block type): you almost certainly want a new module of an appropriate type rather than to extend the parser; the parser itself rarely needs changes.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.