For two decades nginx took its orders as Unix signals. A configuration change meant writing a file and sending SIGHUP, or running nginx -s reload, and then finding out separately whether it had worked. A second way in arrived with version 1.31.5, released on September 2: a REST interface called the Control API that answers two questions the signal never could. What configuration is this server actually running, and did that reload succeed.
It is not new code. The Control API shipped first in NGINX Plus R37.0, the paid long-term support release, and this version moves it into NGINX Open Source. The project published its explainer on September 21, and its own summary of the old arrangement is blunt. Signals are “very stable”, but the method “does not meet modern environment requirements: there are very few available options, no direct feedback messages on errors, and no real extensibility.” Whether a given server can use any of it, though, is decided long before the version number reaches it.
Key facts
- The capability: read the config held in memory by the master process, and trigger a reload that returns an HTTP status code with the reload logs in the response body.
- The provenance: the Control API first shipped in NGINX Plus R37.0, the paid long-term support release, and has now been open sourced into the free core.
- The build: nginx has to be compiled with
--with-control-api, which is not the default. The runtime listener is then opened separately with the-lflag. - The catch: there is no authentication or authorization on it at all, so anything that reaches the socket can read the whole configuration and reload the server.
The Config on Disk Is Not Always the Config in Memory
The API exposes two paths, /1/control/config for the configuration and /1/control/processes for runtime inspection. The more interesting half is the part that reads. nginx has always been able to reject a new configuration and carry on serving the old one, which is a safety feature. It also creates a gap that nobody could see into. In the project’s own description, operators “sometimes fall into a trap where they no longer know what configuration NGINX is then running. The configuration on disk may have completely changed but NGINX is still running some old configuration.”
Until now there was no way to close that gap. The phrasing is unambiguous: “Before Control API there was no method of retrieving that current configuration.” A GET to /1/control/config now returns a JSON array of the files the master process is holding, each with its path and its contents, included files among them.
Worth being clear about what this is not. The Control API reads configuration and triggers reloads. It does not accept one. Configuration is still written to files on disk the way it always was, and the API is the thing that tells you what happened next.
For a fleet operator, that closes a gap between what the control layer thinks it deployed and what the nginx master process is actually running. A panel writes a vhost, calls a reload, and reports success to the customer. If nginx rejected the file, the panel and the server disagree. The customer sees the new settings in the interface and the old ones on the wire, and nothing in between reports the divergence.
A Reload That Answers Back
The second half is the reload itself. A PATCH to the same endpoint triggers it, captures the logs produced during the reload, and returns them in the response. Success comes back as 200 OK, with an empty log array. A broken configuration comes back as 422 Unprocessable Entity, with the reason in the body. The project’s example is an invalid number of arguments in a listen directive.
That replaces a common operational workaround. Before, as the explainer puts it, users “may have had to export and search through logs for this information or potentially check PIDs of worker processes.” There is also a class of failure the old method could not report at all. Socket permission errors surface only in the logs of the new master process, which the old configuration cannot write, and the API now reflects them in the status code. The interface itself, the project says, “does not experience any interruption during reload”.
Out of the Paid Product and Into the Free One
The release announcement lists the Control API among four capabilities “landing directly in open-source core”, and describes this one as “open sourced from F5 NGINX Plus”. The other three widen how nginx reaches a routing decision, including decisions taken on request-body data rather than URI matching alone: predicate variables in location blocks, a JSON parsing module, and early request body inspection. Those are a separate story about what nginx can weigh before it picks a backend.
The stated reason for the API is containers and managed deployments. nginx wanted “configuration and management interfaces that better support using NGINX in containers or behind managed deployments”. The same properties apply to a shared hosting platform, where nginx also sits behind an orchestration layer that has to know whether its last instruction took effect.
No Authentication of Its Own
The security note is short and worth reading twice. The API “provides open access to the NGINX configuration and reload functionality without authentication or authorization.” The recommendation is a Unix domain socket with file permissions locked to root. Binding it to a network address is possible, and on that the project is direct: “we strongly discourage this for security reasons”. It allows that a network address may still be reasonable across a trusted network such as a VPN, or behind a proxy that supplies the access control the API does not have.
Nothing is exposed until someone opens it. The socket does not exist unless the master process is started with -l and a path or address. That makes this a deliberate act rather than a default risk, which is the right way round. It also makes it a foreseeable mistake on a busy platform. An internal network is the kind of place a socket gets opened without much argument, and on a shared server the configuration it exposes can include vhosts belonging to many customers.
The Version Number Tells You the Branch, Not the Build
Having nginx 1.31.5 or later does not mean having the Control API. The project’s configure reference lists --with-control-api among the options that “enable the use of nginx control REST API”, and it is not built by default. A package built without that flag has no API to open, whatever the version string says, and nginx -V is what settles it.
The branch is the other gate. 1.31 is the mainline branch. The stable branch is 1.30, whose current release is 1.30.5, and the feature is not in it. Both branches were patched the same day against a buffer overflow in the HTTP/3 module, 1.31.6 and 1.30.5 on September 15, but only mainline got the API.
What that means on a real platform is worth spelling out, and cPanel supplies a checkable example because it publishes its build specification. cPanel’s EasyApache 4 follows mainline and updated ea-nginx to 1.31.6 on September 16, and its published build specification for that version lists its configure options, --with-control-api not among them. On that evidence the current EasyApache package is built from a source tree that contains the feature, by a configure line that leaves it out.
So the decision that matters is upstream of the operator. Whether to compile the flag in is the packager’s call, and until a package carries it, the question of whether to open the socket never arises. Where the flag is present, the rest follows: whether to open the socket at all, what to open it on, where the project’s own answer is a Unix socket with root-only permissions rather than a network address, and who can reach it.
That last question is the one with the fewest options. The API itself provides no way to hand its capabilities out separately, so access to the listener exposes configuration reads and reloads together, unless an external control layer sits in front of it.
About the Data
The description of the Control API, its endpoints, its response codes and its security posture come from the nginx project’s explainer of September 21 and its announcement of the 1.31.5 release. The feature list and release dates for 1.31.5, 1.31.6 and 1.30.5 come from the project’s changelogs, and the split between the mainline and stable branches from its download page. The provenance in NGINX Plus R37.0 is stated in the release announcement. The build requirement comes from the project’s configure reference, the EasyApache package version from cPanel’s release notes, and its configure options from the published ea-nginx build specification. No adoption figures exist.
Sources
- NGINX Control API: View In-Memory Configuration and Reload via HTTP Requests - NGINX Community Blog
- NGINX 1.31.5: Control API, predicate locations, early body inspection, and more - NGINX Community Blog
- CHANGES - nginx.org
- CHANGES-1.30 - nginx.org
- Download - nginx.org
- Building nginx from Sources - nginx.org
- ea-nginx - cPanel on GitHub
- Release Notes - cPanel & WHM Documentation