nginx has two live branches at any time: an odd-numbered mainline branch that gets new features and fixes every few weeks, and a single even-numbered stable branch, cut each April, that only gets important fixes. Security fixes land in both on the same day, and nginx.org lists every one with vulnerable and fixed version ranges. As of 25 October 2026 that means mainline 1.31.8 and stable 1.30.6.
Every date and version below comes from nginx.org, the project's GitHub repository or the fork's own site. One naming note: this post is about nginx, the web server and reverse proxy, not ingress-nginx, the retired Kubernetes Ingress controller covered in our post on the ingress-nginx retirement.
Key takeaways
- nginx 0.1.0, the first public version, shipped on 4 October 2004. Version 1.0.0 followed on 12 April 2011.
- Mainline versions have an odd minor number (1.29, 1.31) and ship new features roughly every two to six weeks. Stable versions have an even minor number (1.28, 1.30) and a new stable branch is cut every April.
- When a new stable branch is cut, the previous one stops getting releases. The 1.28 branch's last release was 1.28.3 on 24 March 2026; 1.30.0 arrived on 14 April 2026 and every advisory since then names only 1.30 and 1.31 fixed versions.
- SECURITY.md commits to acknowledging reports in 1 to 3 days and fixing within 90 days. Reports go to F5.
- TLS 1.3 became enabled by default in 1.23.4 (March 2023); TLS 1.0 and 1.1 were disabled by default in 1.27.3 (November 2024).
- HTTP/3 arrived as experimental support in 1.25.0 (May 2023), is still labelled experimental, and is the most frequent subject on the advisories page since.
- The advisories page lists 68 entries going back to 2009; 26 were fixed in releases shipped in 2026.
- If a distribution, container image or ingress controller ships your nginx, that packager sets your patch timing, and backports mean its version string may not match upstream ranges.
How did nginx begin, and who looks after it now?
Igor Sysoev and the first public release
nginx.org describes nginx as an HTTP web server, reverse proxy, content cache, load balancer, TCP and UDP proxy and mail proxy, "originally written by Igor Sysoev" and distributed under the 2-clause BSD license. The full CHANGES file starts with nginx 0.1.0 on 4 October 2004, followed by 0.1.1 a week later.
When 1.0.0 shipped on 12 April 2011, the nginx.org announcement said development "was started about 9 years ago" and pointed to a Subversion repository at svn.nginx.org. nginx spent six and a half years in 0.x versions, and that shows on the advisories page: many vulnerable ranges start in the 0.x era because the code dates from then.
From a personal project to a company
On 18 July 2011 Igor Sysoev posted a note on nginx.org saying that, because of the project's growth and the support load, he had "established nginx as a company" to dedicate himself to it full time. The same note promised that nginx would remain free, open source software under the 2-clause BSD license. On 12 October 2011 the news page recorded that NGINX, Inc. had announced Series A funding.
Today the nginx.org front page says enterprise distributions, commercial support and training "are available from F5, Inc.", and the project's SECURITY.md says that "as nginx is supported by F5" the team generally follows the F5 security vulnerability response policy. Vulnerability reports go directly to F5. We did not find the date of the company acquisition on nginx.org itself, so we do not give one here; check F5's own announcements if you need it.
The move to GitHub
The 2024 news archive on nginx.org dates the move to GitHub in three steps:
- 13 May 2024: the nginx.org website project moved to GitHub.
- 5 June 2024: the njs project (nginx's JavaScript module) moved to GitHub.
- 6 September 2024: the nginx project itself officially moved to GitHub. GitHub issues replaced trac.nginx.org and GitHub discussions replaced the nginx mailing list.
The download page now lists github.com/nginx/nginx for the code and github.com/nginx/nginx.org for the website. Issues, pull requests and the SECURITY.md policy live on GitHub, while release announcements, CHANGES files, signed tarballs and the advisories page stay on nginx.org.
How do mainline and stable branches work?
The numbering rule
The nginx.org download page has three headings. On 25 October 2026 it listed mainline nginx-1.31.8, stable nginx-1.30.6, and under "Legacy versions" the last release of every older branch, from 1.28.3 back to 0.5.38, each with a PGP signature and a Windows build. The minor number tells you the branch type:
- Odd minor numbers (1.25, 1.27, 1.29, 1.31) are mainline branches. New features, behaviour changes and new modules land here first.
- Even minor numbers (1.24, 1.26, 1.28, 1.30) are stable branches. Each one begins as a snapshot of the preceding mainline. The 1.30.0 CHANGES entry says only "1.30.x stable branch", and the news item for it says it incorporates "new features and bug fixes from the 1.29.x mainline branch".
The annual stable cut
The CHANGES files show a steady rhythm. Each new stable branch starts in April:
| Stable branch | x.0 release date | Built from mainline |
|---|---|---|
| 1.2 | 23 April 2012 | 1.1.x |
| 1.24 | 11 April 2023 | 1.23.x |
| 1.26 | 23 April 2024 | 1.25.x |
| 1.28 | 23 April 2025 | 1.27.x |
| 1.30 | 14 April 2026 | 1.29.x |
The mainline branch number moves up at about the same time. 1.29.8 was dated 7 April 2026, the stable 1.30.0 followed on 14 April, and mainline 1.31.0 shipped on 13 May 2026 alongside the first stable bugfix, 1.30.1.
How often each branch releases
nginx.org does not publish a release calendar, so the CHANGES record is the guide. Between 13 May and 21 October 2026 mainline shipped nine releases (1.31.0 to 1.31.8), roughly one every two to five weeks. Stable shipped six (1.30.1 to 1.30.6), and every one of them contains at least one "Security" entry in CHANGES-1.30, released the same day as a mainline release with the same fixes. In 2026 the stable branch moved almost entirely because of security fixes.
Older stable branches were quieter: 1.26 ended at 1.26.3 on 5 February 2025, and 1.24 never moved past 1.24.0. Stable activity depends on how many issues are found that year, not on a schedule.
What happens to the old stable branch
This is the detail that matters most for operations. When the new stable branch arrives in April, the old one stops. The 1.28 branch's last release, 1.28.3, is dated 24 March 2026. 1.30.0 came three weeks later. Every advisory on the security page since then, starting with the 1.30.1 and 1.31.0 releases on 13 May 2026, lists fixed versions only for 1.31 and 1.30.
SECURITY.md says fixes go to "all supported stable releases, as well as the mainline version, as applicable". In practice that has meant one stable branch at a time. A 1.28 build from nginx.org sources in late 2026 has no upstream fix for the summer and autumn advisories: upgrade to 1.30, move to mainline, or rely on a packager that backports.
Mainline is not the "unstable" branch
SECURITY.md recommends "the most recent mainline or stable release" without ranking them. Mainline gets every fix first, though some bugs exist only there: the June 2026 news item notes 1.31.2 fixed an HTTP/3 use-after-free that affected only 1.31.0 and 1.31.1.
The real difference is change rate. In 2026, mainline changed the default proxy HTTP version to HTTP/1.1 with keep-alive (1.29.7), started rejecting HTTP/2 and HTTP/3 requests that carry hop-by-hop headers such as "Connection" and "Transfer-Encoding" (1.31.0), and switched HTTP/2 to the RFC 9218 prioritization scheme (1.31.7). Each of those is a good change, and each one can break a fragile client or backend. Stable users meet them once a year, in a single planned upgrade.
Branch comparison: who should run what
| Branch | Version pattern | Release cadence (2026 record) | Who should run it | How fixes arrive |
|---|---|---|---|---|
| Mainline | Odd minor (1.31.x) | Nine releases from May to October 2026 | Teams that test and deploy often, want new features (HTTP/3 improvements, control API) and can absorb behaviour changes | Every bug and security fix lands here first, often with new features in the same release |
| Stable | Even minor (1.30.x) | Six releases from May to October 2026, all with security fixes | Teams that upgrade once a year and want only important fixes in between | Security fixes and selected bug fixes, released the same day as the matching mainline release |
| Legacy (previous stable) | Older even minor (1.28.x and below) | No new upstream releases after the next stable branch is cut | Nobody running nginx.org builds directly; only via a packager that commits to backports | Only through your distribution or vendor, if at all |
| Distribution package | Distro version string, often older | Follows the distribution's security process | Teams that standardise on their OS vendor's lifecycle | Distro backports fixes into its own build; check the distro's tracker, not upstream ranges |
| Fork (for example freenginx) | Its own numbering, overlapping with nginx | Its own schedule | Teams that have chosen the fork deliberately | The fork's own security page and releases |
Timeline: notable nginx versions and what they added
Every row below is taken from the nginx CHANGES file or the nginx.org news archive. Where a feature arrived in stages, each stage has its own row.
| Version | Date | What changed |
|---|---|---|
| 0.1.0 | 4 Oct 2004 | First public release |
| 0.2.2 | 30 Sep 2005 | ssl_protocols and ssl_prefer_server_ciphers directives |
| 1.0.0 | 12 Apr 2011 | First 1.x stable release |
| 1.1.13 | 16 Jan 2012 | TLSv1.1 and TLSv1.2 parameters for ssl_protocols |
| 1.3.15 | 26 Mar 2013 | ngx_http_spdy_module (SPDY) |
| 1.5.10 | 4 Feb 2014 | SPDY module moves to SPDY 3.1 |
| 1.7.4 | 5 Aug 2014 | nginx can be built with BoringSSL and LibreSSL |
| 1.9.0 | 28 Apr 2015 | The stream module (generic TCP proxying) |
| 1.9.1 | 26 May 2015 | SSLv3 disabled by default |
| 1.9.5 | 22 Sep 2015 | ngx_http_v2_module replaces ngx_http_spdy_module |
| 1.9.11 | 9 Feb 2016 | Dynamic modules |
| 1.9.13 | 29 Mar 2016 | UDP support in the stream module |
| 1.11.5 | 11 Oct 2016 | ngx_stream_ssl_preread_module |
| 1.13.0 | 25 Apr 2017 | "TLSv1.3" parameter for ssl_protocols |
| 1.13.9 | 20 Feb 2018 | HTTP/2 server push |
| 1.15.3 | 28 Aug 2018 | TLSv1.3 with BoringSSL; ssl_early_data directive |
| 1.15.4 | 25 Sep 2018 | ssl_early_data works with OpenSSL |
| 1.21.2 | 31 Aug 2021 | OpenSSL 3.0 compatibility |
| 1.21.4 | 2 Nov 2021 | NPN support for HTTP/2 removed (ALPN only) |
| 1.23.4 | 28 Mar 2023 | TLSv1.3 enabled by default |
| 1.25.0 | 23 May 2023 | Experimental HTTP/3 support |
| 1.25.1 | 13 Jun 2023 | Per-server http2 directive; HTTP/2 server push removed |
| 1.26.0 | 23 Apr 2024 | Stable branch with experimental HTTP/3 |
| 1.27.3 | 26 Nov 2024 | TLSv1 and TLSv1.1 disabled by default |
| 1.29.0 | 24 Jun 2025 | Response code 103 from proxy and gRPC backends; early_hints directive |
| 1.29.1 | 13 Aug 2025 | 0-RTT in QUIC with OpenSSL 3.5.1 or newer; TLSv1.3 certificate compression off by default |
| 1.29.4 | 9 Dec 2025 | HTTP/2 to backends in the proxy module; Encrypted ClientHello with the OpenSSL ECH feature branch |
| 1.29.7 | 24 Mar 2026 | Multipath TCP; default proxy HTTP version becomes HTTP/1.1 with keep-alive |
| 1.29.8 | 7 Apr 2026 | OpenSSL 4.0 compatibility; max_headers directive |
| 1.30.0 | 14 Apr 2026 | Stable branch with Early Hints, HTTP/2 to backend, ECH, sticky sessions |
| 1.31.0 | 13 May 2026 | HTTP forward proxy support; hop-by-hop headers rejected in HTTP/2 and HTTP/3 |
| 1.31.5 | 2 Sep 2026 | Control API, predicate locations, ngx_http_json_module |
| 1.31.7 | 14 Oct 2026 | RFC 9218 HTTP/2 prioritization; MaxMind DB format for GeoIP modules; QUIC binary upgrade with quic_bpf |
SPDY, then HTTP/2
The SPDY module arrived in 1.3.15 (March 2013). In September 2015, 1.9.5 introduced ngx_http_v2_module, which CHANGES says "replaces ngx_http_spdy_module". Protocol support in nginx gets replaced, not layered: HTTP/2 server push arrived in 1.13.9 (February 2018) and was removed in 1.25.1 (June 2023), which also deprecated the http2 parameter of listen in favour of a per-server http2 directive. An HTTP/2 config copied from a 2017 tutorial may use both outdated forms.
The stream module and dynamic modules
The stream module in 1.9.0 (April 2015) made nginx a general TCP proxy, and 1.9.13 added UDP. It later gained ssl_preread for routing on SNI without terminating TLS, virtual servers (1.25.5) and OCSP stapling (1.27.2), which is why nginx sits in front of databases and brokers, not only websites.
Dynamic modules arrived in 1.9.11 (February 2016), letting modules be built as shared objects and loaded with load_module. That was an operational win and a supply chain question: a dynamic module must match the binary that loads it, and third-party modules have their own maintainers and schedules.
TLS: from SSLv3 to TLS 1.3 by default
The TLS story is a series of default changes, each years after the protocol support itself:
ssl_protocolshas existed since 0.2.2 in 2005. TLS 1.1 and 1.2 parameters arrived in 1.1.13 in January 2012.- SSLv3 was disabled by default in 1.9.1 (May 2015).
- The TLSv1.3 parameter arrived in 1.13.0 (April 2017), and TLS 1.3 early data (0-RTT) arrived in 1.15.3 and 1.15.4 in 2018.
- TLS 1.3 was enabled by default in 1.23.4 (March 2023).
- TLS 1.0 and 1.1 were disabled by default in 1.27.3 (November 2024), which reached stable users with 1.28.0 in April 2025.
The current ngx_http_ssl_module documentation lists these defaults: ssl_protocols TLSv1.2 TLSv1.3, ssl_ciphers HIGH:!aNULL:!MD5, ssl_session_tickets on, ssl_early_data off and ssl_prefer_server_ciphers off. The key operational point is that a default only helps you if you have not overridden it. An ssl_protocols TLSv1 TLSv1.1 TLSv1.2; line copied from an old guide keeps the old protocols enabled after the upgrade. Our post on TLS 1.3 versus TLS 1.2 and what to disable covers the protocol side in more detail.
Library support has moved too. CHANGES records BoringSSL and LibreSSL builds from 1.7.4 (2014), OpenSSL 3.0 compatibility in 1.21.2 (2021) and OpenSSL 4.0 compatibility in 1.29.8 (April 2026). Which TLS library your nginx links against is part of your attack surface, and it is usually patched by a different team on a different schedule.
HTTP/3 and QUIC
HTTP/3 arrived as "experimental HTTP/3 support" in 1.25.0 on 23 May 2023 and reached stable users with 1.26.0 on 23 April 2024, whose news item still described it as experimental. The QUIC documentation page on nginx.org says support for QUIC and HTTP/3 "is available since 1.25.0" and is included in the nginx.org Linux binary packages.
Building it yourself has specific requirements, all from the nginx.org QUIC and ngx_http_v3_module pages:
- The module is not built by default; it needs the
--with-http_v3_moduleconfigure option. - It needs OpenSSL 1.1.1 or newer. OpenSSL 3.5.1 or newer is recommended. With older OpenSSL, nginx uses an OpenSSL compatibility layer that does not support early data.
- BoringSSL, LibreSSL or QuicTLS can be used instead.
- The module cannot be built on Win32.
- QUIC needs TLS 1.3, which is enabled by default in
ssl_protocols.
In configuration, listen takes a quic parameter, usually with reuseport for multiple workers. quic_retry on enables address validation, ssl_early_data on enables 0-RTT, quic_gso on enables Linux segmentation offload and quic_host_key sets the token key. The docs recommend the same port for HTTP/3 and HTTPS.
The module page also says, as of October 2026, "The module is experimental, caveat emptor applies." That label has a direct security consequence that most teams miss. SECURITY.md excludes from the security release process "issues with experimental features which result only in availability impact". If an HTTP/3 bug can only crash a worker, it may be fixed as an ordinary bug rather than with an advisory. Memory corruption and data integrity bugs in HTTP/3 have still received advisories, as the next section shows.
The HTTP/3 stack has kept moving since 2023. CHANGES records path MTU discovery (1.25.2), CUBIC congestion control (1.27.5), 0-RTT with OpenSSL 3.5.1 (1.29.1), limits on QUIC stateless reset packets (1.29.6), and reconfiguration and binary upgrade with quic_bpf (1.31.7).
njs and the ACME module have their own release trains
njs, nginx's JavaScript module, runs handlers at fixed integration points and "is not a standalone application runtime", per its docs. It added the QuickJS engine in 0.8.6 (2 October 2024), and njs 1.0.0 (23 June 2026) deprecated its built-in engine in favour of QuickJS. The news page lists njs 0.9.9, 1.0.1 and 1.0.2 in 2026 with their own security fixes, shipped in njs releases, not nginx releases. The nginx ACME module also versions separately (nginx-acme 0.3.0 on 18 November 2025, 0.4.0 with ACME Renewal Information on 20 April 2026). If you run either, track the module version as well as nginx's.
The control API moved from commercial to open source
The switches page documents a -l option in 1.31.5 that enables the "nginx control REST API" on a UNIX-domain socket or port, and notes it was part of the commercial subscription from 1.29.8 until 1.31.5. Features do move between editions, so check the docs for your version. Any management API is also control plane surface; SECURITY.md draws the line: the data plane handles traffic, the control plane governs configuration, and "misconfigurations or vulnerabilities in the control plane can cause improper behavior in the data plane". Bind it to a UNIX socket with tight permissions or a loopback address, never a public interface.
How does nginx publish security advisories?
The reporting and fix process
SECURITY.md in the GitHub repository is the authoritative description. In summary:
- Report vulnerabilities privately, directly to F5. If someone reports a vulnerability that is already public, the team may ask to handle it through the private process anyway.
- Fixes are created and tested by the core team in a private GitHub fork. The reporter may be invited to help.
- Privately disclosed vulnerabilities are embargoed by default until the fix is released.
- The team commits to disclosure with "sufficient detail, such as the CVSS score and vector".
- Service level objectives: acknowledge every report in 1 to 3 days; develop and release fixes within 90 days of disclosure, with extensions agreed with the reporter; address publicly disclosed zero-day issues as soon as possible.
The policy puts confidentiality and integrity issues first. Availability issues qualify only if they are in a standard module, come from traffic it is meant to handle, are not mitigated by timeouts, rate limits or buffer sizes, and cause "highly asymmetric, extreme resource consumption". Crashes from local file or upstream response content are excluded, as are availability-only issues in experimental features. Configuration files, modules, certificate and key pairs, nginx JavaScript and local files are trusted, so a bug that needs a malicious config or module is not a vulnerability under this policy; securing those inputs is your job.
What an advisory looks like
The security advisories page at nginx.org/en/security_advisories.html is a single list, newest first. Each entry has a short title, a severity (none, minor, low, medium or major), a link to the advisory text, the CVE identifier, a "Not vulnerable" list of fixed versions per branch and a "Vulnerable" range. Older entries also link to a patch file and its PGP signature, and the page notes that patches are signed with one of the keys on the PGP keys page.
The news page announces each stable and mainline pair together (on 14 October 2026, 1.30.6 and 1.31.7 with five fixes), and CHANGES marks each fix with "Security:". Track three pages: news for announcements, advisories for version ranges, and the CHANGES file for your branch.
How busy has it been?
The advisories page lists 68 entries, the oldest from 2009. The count by year is uneven. There were a handful a year through the 2010s, one in 2021, two in 2022, seven in 2024 and two in 2025. Then 26 entries were fixed in releases shipped in 2026, more than a third of the whole list in one year. The page does not explain the jump. It lines up with a lot of new code (HTTP/3, HTTP/2 to backends, forward proxying) and, in the credit lines in CHANGES, with reports from many outside researchers. Whatever the cause, it changed the operational picture: in 2026, a stable nginx user needed six upgrades between May and October.
Of the 68 entries, 42 are rated medium, 15 major, 9 low, one minor and one none. Several 2026 entries list vulnerable ranges starting in the 0.x era, meaning the flawed code shipped in every branch since then.
Which modules have needed the most fixes?
Counting entries on the advisories page by the module or feature named in the title gives a clear picture. We describe the patterns here, not the individual bugs.
| Area | Entries on the advisories page | Pattern |
|---|---|---|
| HTTP/3 and QUIC (ngx_http_v3_module) | 10, all since 2024 | New protocol code; memory safety bugs, address spoofing, request body handling |
| MP4 streaming (ngx_http_mp4_module) | 7, from 2012 to 2026 | Parsing an untrusted, complex file format; overflows and memory disclosure |
| DNS resolver | 6, from 2011 to 2026 | Parsing DNS responses; use-after-free and overwrite bugs |
| HTTP/2 | 5 in 2018 and 2019, plus 2 in 2026 in HTTP/2 proxying code | Mostly resource exhaustion from protocol abuse; later, backend proxying |
| Windows-specific path handling | 4, from 2010 to 2012 | Windows filename aliases and streams bypassing location rules |
| Mail proxy | 4, from 2014 to 2026 | STARTTLS injection, authentication handling |
| SPDY | 2, in 2014 | Memory corruption in the module later replaced by HTTP/2 |
| Rewrite, charset, SSI, scripting | Several in 2026 | Old, core code paths with newly found memory bugs |
Three lessons follow. New protocol code is where fixes cluster (SPDY in 2014, HTTP/2 in 2018 and 2019, HTTP/3 from 2024), so a young protocol module means more frequent upgrades. Modules that parse complex, untrusted formats (MP4 files, DNS responses) keep needing fixes for years, so leave out the ones you do not use. And old code is not safe because it is old: several 2026 advisories hit rewrite, charset and SSI code with ranges reaching back to 0.x. Know which modules your binary contains (nginx -V) and which your configuration uses.
What forks and derivatives exist?
freenginx
freenginx describes itself as "an effort to preserve free and open development of nginx", originally written by Igor Sysoev, distributed under a 2-clause BSD-like license. Its 2024 news archive dates the project's start to 14 February 2024, with the stated goal "to keep nginx development free from arbitrary corporate actions".
freenginx follows the same odd and even branch scheme. Its news page records freenginx-1.26.0 stable on 9 April 2024, freenginx-1.30.0 stable on 14 April 2026 (including Encrypted Client Hello support, GeoIP2 databases in the GeoIP module and XSLT module hardening), freenginx-1.30.1 stable on 2 June 2026, and freenginx-1.31.4 mainline on 1 September 2026.
Here is the trap: freenginx 1.31.4 and nginx 1.31.4 share a version number but are not the same code. They have different release dates, different change logs and different security pages. If your inventory records only "nginx 1.31.4", you cannot tell which one you have, and you cannot match it to the right advisories. freenginx's own server banner identifies itself as freenginx (its 404 page footer reads "freenginx/1.31.4"), so the binary name and the banner are the first places to look.
Other derivatives and bundles
nginx code also reaches production through commercial distributions from F5, through F5's Kubernetes projects linked from the nginx.org menu (github.com/nginx/kubernetes-ingress and github.com/nginx/nginx-gateway-fabric), through the separate community ingress-nginx controller, and through platforms that bundle an nginx build with their own modules. Each has its own versions, release train and advisories, so record them by what they are, not by the nginx version inside.
How to track which one you run
Record four fields for every nginx-based component:
- Distribution source: nginx.org package, distribution package, container image, fork, commercial build or embedded in another product.
- Upstream base version: the nginx (or freenginx) version from
nginx -v. - Package or product version: the distro package version string, image digest or controller version.
- Build details: the TLS library and version, and the list of compiled-in and dynamic modules from
nginx -V.
With those four fields you can answer "are we affected?" for any advisory in minutes instead of days.
How is nginx bundled, and why does the source matter for patch timing?
nginx.org Linux packages
nginx.org publishes its own Linux package repositories for stable and mainline. The linux_packages page shows the stable repository as the default and documents a separate mainline repository you can enable. Packages are signed. The page tells you to verify the signing key fingerprint 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 before trusting it, and notes that the output may show other keys used to sign packages.
Distribution packages
Operating system distributions build nginx themselves. They usually pick a version when the distribution release is made and then backport security fixes into that version for the life of the release. That has two consequences:
- Your version string can be older than the upstream fixed version and still be patched. A distro package labelled with a 1.24 or 1.26 base can include fixes for advisories that upstream only fixed in 1.30 and 1.31. You need the distribution's security tracker to know.
- Your patch timing depends on the distribution's process, not nginx.org's. The fix may land the same day or later, and some fixes for features the distribution does not build (for example HTTP/3 if it is not compiled in) may not be needed at all.
Container images
Container images inherit both problems. The image tag names an nginx version, but the TLS library comes from whichever distribution the image was built on, and the image only updates when someone rebuilds it. A pinned tag that has not been rebuilt since spring carries spring's nginx and spring's OpenSSL. The fix is a rebuild and redeploy, not a config change.
Ingress controllers and gateways
In Kubernetes, nginx usually arrives inside a controller image. The controller project decides which nginx version and which modules to ship and when to update. The Kubernetes blog post of 11 November 2025 announced that the community ingress-nginx controller would get best-effort maintenance until March 2026 and, after that, "no further releases, no bugfixes, and no updates to resolve any security vulnerabilities". It also noted that the project's flexibility, including the "snippets" annotations that allowed arbitrary nginx configuration, had come to be seen as a serious security problem. So an ingress-nginx deployment in late 2026 carries whatever nginx it last shipped with; nginx fixes released after March 2026 do not reach it through the controller's own releases.
Step by step: check what you run and plan an upgrade
The commands below are read-only except where noted. Run them on a test host first if you are unsure.
1. Find the version and build details
# Version only
nginx -v
# Version, compiler and configure arguments
nginx -V 2>&1
# One configure option per line, to see compiled-in modules and the TLS library build flags
nginx -V 2>&1 | tr ' ' '\n' | grep -E '^--(with|without|add)'
The switches page documents -v as printing the version and -V as printing "nginx version, compiler version, and configure parameters". On builds linked against OpenSSL the output usually also names the OpenSSL version it was built with. Look for:
--with-http_v3_module: HTTP/3 and QUIC are compiled in.--with-http_v2_module: HTTP/2.--with-streamand--with-mail: the stream and mail proxies.--with-http_mp4_module,--with-http_dav_module,--with-http_slice_module: modules that have appeared in advisories.--add-moduleand--add-dynamic-module: third-party modules compiled into or alongside the binary.
If the binary banner says freenginx, track it against freenginx releases, not nginx.org.
2. Find dynamic modules and what the config uses
# Dynamic modules loaded by the configuration
sudo nginx -T 2>/dev/null | grep -E '^\s*load_module'
# Protocol and feature directives actually in use
sudo nginx -T 2>/dev/null | grep -nE '\b(listen|http2|http3|quic_|ssl_protocols|ssl_ciphers|ssl_early_data|resolver|mp4|ssi|dav_methods|slice)\b'
nginx -T is the same as -t but also dumps the full configuration (available since 1.9.2). The dump includes every included file. Do not paste it into tickets or chat without checking it first: it can include internal hostnames, upstream addresses and file paths. Our post on whether nginx access logs record secrets in query strings covers a related exposure in log configuration.
3. Find out where the binary came from
# Debian and Ubuntu
dpkg -S "$(command -v nginx)"
apt-cache policy nginx
# RHEL, Fedora and derivatives
rpm -qf "$(command -v nginx)"
rpm -q --changelog nginx | head -40
# In a container
docker image inspect --format '{{.Id}} {{.Created}}' your-image:tag
This tells you whether you are on an nginx.org package, a distribution package or something else, and when it was last rebuilt. For distribution packages, the changelog often lists the backported fixes by CVE identifier.
4. Compare with the advisories page
For an nginx.org build, compare your version with each advisory's "Not vulnerable" and "Vulnerable" lists on nginx.org/en/security_advisories.html. The ranges are written per branch, for example "Not vulnerable: 1.31.7+, 1.30.6+". If your version is inside a vulnerable range and below the fixed version for your branch, you need to upgrade.
Two refinements make this faster and more accurate:
- Check whether the affected module is compiled in and used. An HTTP/3 advisory does not affect a binary built without
--with-http_v3_module. A ngx_http_mp4_module advisory does not affect a config that never usesmp4. Patch anyway, but use this to prioritise. - For distribution packages, use the distribution's tracker instead of the upstream ranges, as explained above.
5. Test the configuration before any change
sudo nginx -t
-t checks syntax and tries to open the files referenced in the configuration. Run it with the new binary against your current config before you switch. If you build your own packages, run it in CI with the candidate binary.
6. Read the CHANGES entries between your version and the target
For a stable upgrade such as 1.28 to 1.30, read the 1.29.x entries in the mainline CHANGES file and look for "Change:" lines. That move includes TLSv1.3 certificate compression off by default (1.29.1), HTTP/1.1 with keep-alive as the default proxy version (1.29.7), which fragile backends will notice, and QUIC logging level changes (1.29.0) that affect alert rules matching log text. Within 1.31.x, watch 1.31.0 rejecting hop-by-hop headers in HTTP/2 and HTTP/3, 1.31.4 always sending ":authority" or "Host" to backends, and 1.31.7 changing HTTP/2 prioritization.
7. Upgrade and reload
The exact steps depend on how you install nginx. For an nginx.org package on Debian or Ubuntu:
sudo apt update
apt-cache policy nginx # confirm the candidate version comes from nginx.org
sudo apt install --only-upgrade nginx
nginx -v
sudo nginx -t && sudo systemctl reload nginx
For a container, change the base image tag or digest, rebuild, run nginx -t in the new image in CI, then roll out. For a controller, follow its release notes, or plan a migration if it is retired.
The switches page documents -s reload as starting new workers with the new configuration; it does not load a new binary. After a package upgrade, make sure the new binary is running (a restart or the binary upgrade procedure) and check the process start time.
8. Decide your branch on purpose
Pick a branch based on how often you can safely deploy:
- If you can test and deploy nginx changes every few weeks, mainline gets you fixes first and new protocol work sooner.
- If you deploy once or twice a year, use stable and schedule an upgrade each May, after the April stable cut, so you never sit on a branch that has stopped receiving fixes.
- If your OS vendor's lifecycle is your patch policy, use the distribution package and track the distribution's advisories.
Write the choice down. The worst outcome is an accidental branch: a hand-built 1.28 binary from two years ago that nobody owns.
Common mistakes
Confusing ingress-nginx with nginx. They are different projects with different maintainers. ingress-nginx stopped receiving releases after March 2026, per the Kubernetes blog; nginx is actively maintained. Upgrading nginx on a host does nothing for a cluster running ingress-nginx.
Staying on the old stable branch after April. A 1.28 build from nginx.org sources has no upstream fix for advisories published from May 2026 onwards.
Running unmaintained third-party modules. SECURITY.md lists modules among the trusted inputs, so a third-party module bug is your risk. Many such modules have one maintainer, lag behind nginx or are abandoned, and each dynamic module must be rebuilt for the nginx that loads it. Keep a list of every --add-module and load_module, who maintains it and when it last released.
Old TLS settings from copied configs. Defaults have improved (TLS 1.0 and 1.1 off by default since 1.27.3), but an explicit ssl_protocols or ssl_ciphers line overrides the default. Configs copied from guides written before 2020 often enable TLS 1.0 and 1.1 or long cipher lists. Remove the line to inherit the default, or set it to TLSv1.2 TLSv1.3 deliberately.
Hiding the version but never patching. server_tokens off removes the version from the Server header and error pages, but it does not change the binary. Behaviour-based checks still find unpatched servers, and you lose an easy way to audit your own fleet.
Comparing distro versions with upstream ranges. Backported fixes hide under old version numbers. Use the distribution's tracker.
Forgetting the TLS library. QUIC 0-RTT, ECH and certificate compression depend on library versions, and a TLS library flaw is fixed by updating the library and restarting nginx.
Enabling experimental HTTP/3 without a faster patch cycle. HTTP/3 has had 10 advisory entries since 2024 and its module page still says "caveat emptor". If you enable it, commit to upgrading promptly and monitor the advisories page.
FAQ
What is the difference between nginx mainline and stable?
Mainline has an odd minor version number and gets new features, behaviour changes and all fixes, with releases every few weeks. Stable has an even minor number, is cut from mainline every April, and only gets important fixes, mostly security. Both get security fixes on the same day.
Which nginx branch should I use in production?
The project's SECURITY.md recommends the most recent mainline or stable release. Use mainline if you can test and deploy often; use stable if you upgrade on a yearly cycle. Either way, do not stay on a stable branch after the next one is released.
When was nginx first released?
nginx 0.1.0, the first public version, is dated 4 October 2004 in the nginx CHANGES file. nginx 1.0.0 followed on 12 April 2011.
Does nginx support HTTP/3?
Yes. Experimental HTTP/3 and QUIC support arrived in 1.25.0 on 23 May 2023 and is included in nginx.org Linux packages. The module has to be built with --with-http_v3_module, works best with OpenSSL 3.5.1 or newer, and its documentation still describes it as experimental.
When did nginx enable TLS 1.3 by default?
TLS 1.3 became enabled by default in 1.23.4 on 28 March 2023. The TLSv1.3 option itself has been available since 1.13.0 in April 2017. TLS 1.0 and 1.1 were disabled by default in 1.27.3 in November 2024.
Where are nginx security advisories published?
On nginx.org/en/security_advisories.html, with release announcements on the nginx.org news page and "Security:" entries in each branch's CHANGES file. Vulnerabilities are reported privately to F5, as described in SECURITY.md in the nginx GitHub repository.
How fast does nginx fix security vulnerabilities?
SECURITY.md commits to acknowledging reports within 1 to 3 days and releasing fixes within 90 days of disclosure, with extensions agreed with the reporter. Publicly disclosed zero-day issues are addressed as soon as possible.
Is freenginx the same as nginx?
No. freenginx is a separate project started on 14 February 2024 that describes itself as an effort to preserve free and open development of nginx. It uses similar version numbers but has its own code, releases and security information, so track it separately.
Is ingress-nginx the same as nginx?
No. ingress-nginx is a Kubernetes Ingress controller that embeds nginx. The Kubernetes project announced its retirement on 11 November 2025, with best-effort maintenance until March 2026. nginx itself continues to be maintained.
Where Safeguard fits
The fit here is partial, and it is worth being clear about where. nginx usually reaches production as a binary from a distribution package, an nginx.org package, a container image or a controller image, not as a library dependency in your code. Safeguard does not patch the nginx binary on a host you manage, and it does not replace the distribution or vendor that ships your nginx build; those fixes still come from nginx.org, your distribution or your vendor.
Where Safeguard helps is the inventory and the gate. Scanning a container image with safeguard scan --image <name> builds an inventory of the packages inside it, which is how you find every image that still carries an old nginx or TLS library package, and the platform shows which projects contain a given component and version. Policies and gates in CI can then stop images with known vulnerable versions from shipping: gate actions are Block, Warn and Notify, with approval through exceptions when a team needs to ship anyway. Where nginx sits in front of application code you build, the same scans cover the open source dependencies of that code, and reachability analysis helps rank which findings your application actually calls; how much that narrows your list depends on the codebase and should be measured during evaluation. Gold Open Source at gold.safeguard.sh gives free CVE intelligence with affected and fixed versions for open source components.
nginx is one component, but it rarely ships alone: the image it runs in, the TLS library it links and the application behind it all pull in open source packages that need the same version tracking described above. The steps below apply to those dependencies and images you build, while fixes for the nginx binary itself still come from nginx.org, your distribution or your vendor.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.
3. Gold Registry: start from components that are already fixed
Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | Safeguard policies and gates in CI |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
The first demo is a real Safeguard CLI session. It shows the assistant reading a finding and its advisory in a repository, asking before any command that changes something, editing a dependency version and running the install and tests. The same flow applies when the fix for an nginx-related finding is a change you own, such as bumping a base image tag in a Dockerfile or an nginx package pin, and you want a reviewed, tested change rather than a ticket.
Click through it at your own pace, or open it full screen.
The second demo sets up the Safeguard runner on your own machine, approves it with its device code and then scans from the terminal. That is the natural place to scan the container images that carry nginx in your build environment, before they reach a registry.
Click through it at your own pace, or open it full screen.
The third demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude can use. With that connection, a question like "which of our projects contain this component and version" can be answered from your Safeguard data during an advisory review.
Click through it at your own pace, or open it full screen.
To try it on your own images and repositories, download Safeguard or read the CLI documentation.
Quick check
nginx 1.30.x is the current stable branch. What happens to 1.28.x?
It stops receiving upstream releases. 1.28.3, dated 24 March 2026, was its last release, and advisories published after 1.30.0 list fixed versions only for 1.30 and 1.31. Move to 1.30 or mainline, or rely on a packager that backports fixes.
Your distribution's nginx package reports a 1.24-based version. Is it vulnerable to an issue fixed upstream in 1.30.6?
Not necessarily. Distributions backport fixes into older versions. Check the distribution's security tracker or package changelog rather than comparing the version string with nginx.org's ranges.
Does turning off server_tokens protect an unpatched nginx?
No. It hides the version in headers and error pages but does not change the code that runs. Patch on schedule and keep your own inventory of versions.
Sources
- nginx CHANGES (mainline change log)
- nginx CHANGES-1.30 (stable change log)
- nginx CHANGES-1.28
- nginx CHANGES-1.26
- nginx CHANGES-1.24
- nginx CHANGES-1.0
- nginx security advisories
- nginx download page
- nginx news
- nginx news archive: 2025
- nginx news archive: 2024
- nginx news archive: 2019
- nginx news archive: 2011
- nginx about page
- nginx documentation index
- nginx Linux packages
- Support for QUIC and HTTP/3
- Module ngx_http_v3_module
- Module ngx_http_v2_module
- Module ngx_http_ssl_module
- Module ngx_http_core_module
- Module ngx_stream_core_module
- Core functionality (load_module)
- Command-line parameters
- Building nginx from sources
- njs scripting language
- nginx PGP keys
- nginx GitHub repository
- nginx SECURITY.md
- nginx CONTRIBUTING.md
- freenginx news
- freenginx news archive: 2024
- freenginx about
- Kubernetes blog: Ingress NGINX Retirement: What You Need to Know (11 Nov 2025)
Last reviewed: 25 October 2026. nginx releases often; check the nginx.org news and advisories pages for the latest versions.