nginx/nginx
Module (ngx_module_t)
Active contributors: Sergey Kandaurov, Maxim Dounin
What it is
A module is the unit of feature in nginx. Every directive, every protocol handler, every variable, every load balancer, every filter is registered through an ngx_module_t. The static array ngx_modules[] (generated at build time by auto/modules into objs/ngx_modules.c) is the source of truth for what features the binary has. Dynamic modules use the same struct but ship as .so files.
Definition
src/core/ngx_module.h:
struct ngx_module_s {
ngx_uint_t ctx_index; /* index within its type */
ngx_uint_t index; /* index across all modules */
char *name; /* set by NGX_MODULE_V1 / dynamic */
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t version; /* nginx_version */
const char *signature; /* compile-time feature mask */
void *ctx; /* type-specific hook table */
ngx_command_t *commands; /* directives this module owns */
ngx_uint_t type; /* NGX_*_MODULE constant */
/* lifecycle hooks */
ngx_int_t (*init_master)(ngx_log_t *log);
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
void (*exit_thread)(ngx_cycle_t *cycle);
void (*exit_process)(ngx_cycle_t *cycle);
void (*exit_master)(ngx_cycle_t *cycle);
/* padding for ABI evolution */
uintptr_t spare_hook0;
/* ... 7 more spare hooks ... */
};The NGX_MODULE_V1 macro initializes the version + signature + index fields; NGX_MODULE_V1_PADDING zeroes the spare hooks. Together they keep the struct layout stable across nginx versions so dynamic modules built against one version can load into another (within the bounds of the signature compatibility check).
Module types
type is one of:
| Constant | Hex | "Friendly name" | Hook table type |
|---|---|---|---|
NGX_CORE_MODULE |
0x434F5245 | "CORE" | ngx_core_module_t |
NGX_EVENT_MODULE |
0x544E5645 | "EVNT" | ngx_event_module_t |
NGX_HTTP_MODULE |
0x50545448 | "HTTP" | ngx_http_module_t |
NGX_MAIL_MODULE |
0x4C49414D | "MAIL" | ngx_mail_module_t |
NGX_STREAM_MODULE |
0x4d525453 | "STRM" | ngx_stream_module_t |
NGX_CONF_MODULE |
0x464E4F43 | "CONF" | (the include directive) |
The 4-character ASCII tags are the integer values (read backwards on x86). They're a sanity check at module load time.
Hook tables
The ctx pointer points to a type-specific struct that adds module-type-specific hooks beyond the lifecycle ones in ngx_module_t. For HTTP:
typedef struct {
ngx_int_t (*preconfiguration)(ngx_conf_t *cf); /* register variables */
ngx_int_t (*postconfiguration)(ngx_conf_t *cf); /* attach phase handlers */
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
void *(*create_loc_conf)(ngx_conf_t *cf);
char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;Hooks fire in this order:
preconfiguration— before parsing. Modules register variables here.- Parsing — directives from
commands[]fire in order they appear innginx.conf.create_*_confallocates, the directive's setter fills. init_main_conf/merge_*_conf— after parsing. Fill in defaults, merge from outer scope.postconfiguration— attach phase handlers, capture filter chain pointers.
Setting the right hook for a feature is the central question when writing a module.
Lifecycle hooks
Beyond the type-specific hooks, every module has the lifecycle ones in ngx_module_t:
| Hook | Fires |
|---|---|
init_master |
Once in the master before the first cycle. Almost always NULL. |
init_module |
After ngx_init_cycle builds a new cycle (startup + every reload) |
init_process |
After fork(), in each worker. Open per-worker resources. |
init_thread |
(Reserved; not currently used.) |
exit_thread |
(Reserved.) |
exit_process |
Worker is exiting. Close per-worker resources. |
exit_master |
Master is exiting. Almost always NULL. |
Modules typically use init_module to set up shared zones and init_process to open per-worker fds.
commands[]
The directive table. ngx_command_t:
struct ngx_command_s {
ngx_str_t name; /* directive name */
ngx_uint_t type; /* context + arity flags */
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t conf; /* which conf to write into */
ngx_uint_t offset; /* offset within that conf */
void *post; /* extra arg for the setter */
};commands[] is terminated by ngx_null_command. See systems/configuration for the list of context flags, common setters, and how the parser dispatches directives.
A minimal HTTP module
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
typedef struct {
ngx_flag_t enable;
} ngx_http_my_loc_conf_t;
static ngx_int_t ngx_http_my_handler(ngx_http_request_t *r);
static char *ngx_http_my_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void *ngx_http_my_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_my_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);
static ngx_command_t ngx_http_my_commands[] = {
{ ngx_string("my_directive"),
NGX_HTTP_LOC_CONF | NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_my_loc_conf_t, enable),
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_my_module_ctx = {
NULL, /* preconfiguration */
ngx_http_my_init, /* postconfiguration */
NULL, /* create main conf */
NULL, /* init main conf */
NULL, /* create srv conf */
NULL, /* merge srv conf */
ngx_http_my_create_loc_conf, /* create loc conf */
ngx_http_my_merge_loc_conf, /* merge loc conf */
};
ngx_module_t ngx_http_my_module = {
NGX_MODULE_V1,
&ngx_http_my_module_ctx, /* module context */
ngx_http_my_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_my_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
if (h == NULL) return NGX_ERROR;
*h = ngx_http_my_handler;
return NGX_OK;
}Build via --add-module=/path/to/dir (static) or --add-dynamic-module=... (loadable .so).
Module signature
NGX_MODULE_SIGNATURE is a compile-time string of 0/1 bits encoding which NGX_HAVE_* features the module was built against. At module-load time, the host nginx checks the signature matches; if not, load_module refuses. This is what prevents loading a module built against --with-debug into a non-debug nginx, or vice versa.
The signature is generated from NGX_MODULE_SIGNATURE_0 through NGX_MODULE_SIGNATURE_34 (see src/core/ngx_module.h).
ngx_modules[] and ngx_module_names[]
Both are auto-generated by auto/modules and live in objs/ngx_modules.c:
ngx_module_t *ngx_modules[] = {
&ngx_core_module,
&ngx_errlog_module,
&ngx_conf_module,
/* ... etc ... */
NULL
};
char *ngx_module_names[] = {
"ngx_core_module",
"ngx_errlog_module",
/* ... */
NULL
};The order matters: init_module, init_process, and especially filter-chain registration all depend on it. auto/modules uses an explicit ORDER list to keep things consistent across builds.
Cross-references
- systems/configuration — how directives flow into module configs
- primitives/cycle — modules run hooks against the cycle
- how-to-contribute/patterns-and-conventions — module-style conventions
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.