Sign inSign up

chainstack/ingress-nginx

By chainstack

•Updated 19 days ago

Image
0

10K+

chainstack/ingress-nginx repository overview

⁠ingress-nginx

Chainstack build of nginx-ingress-controller, with custom nginx modules baked inside.

Modules:

⁠What this image is

ingress-nginx was retired upstream on 2026-03-24, so no patched controller release will ever ship again. This image therefore builds nginx itself rather than inheriting it from the upstream controller image — that is the only way to pick up nginx security fixes now.

Upstream's build tree is fetched at build time from its pinned, archived tag rather than vendored into this repository, so this stays a Dockerfile-only project. The two modifications we make to that tree are the two commands in the upstream-src stage of the Dockerfile:

  1. bump NGINX_VERSION (currently to 1.30.4, for CVE-2026-42533)
  2. delete 19_*log_escape_non_ascii.patch — 2 of its 10 hunks no longer apply to 1.30.4, and the directive it adds is referenced nowhere in the controller, so rebasing it would carry a patch nothing uses. 31 of the 32 patches apply unchanged.
  3. patch ngx_devel_kit with patches-ndk/ndk-complex-value-end.patch. nginx 1.30.4 moved the rewrite-engine stack push into a new complex_value_end code as part of the CVE fix; NDK's private copy of ngx_http_rewrite_value() never gained it, so every set_* directive with a variable argument (the controller emits set_escape_uri for auth-signin ingresses) segfaults the worker. Upstream NDK is unfixed. This caused the 2026-09-08 prod-console SSO outage.

All are wrapped in grep/test guards. Without them an upstream layout change would make sed match nothing and the build would ship a vulnerable nginx while the tag and image labels claimed otherwise. The guards turn that into a failed build.

The smoke stage then starts the freshly built nginx with the auth-signin constructs and a set_by_lua_block, sends real requests, and fails the build on a worker crash or on any value that differs from what nginx 1.25.5 returned (smoke/expected.txt). Compiling a third-party module against a new nginx proves nothing about whether it still works.

The Go controller is not rebuilt — its source is unchanged, so the published upstream binaries (dbg, nginx-ingress-controller, wait-shutdown) are relayered onto the patched nginx.

/etc is taken from upstream source, not from the published controller image, whose /etc/nginx/modules/*.so are compiled against the old nginx and are not binary compatible with the new one.

⁠Versions

Everything is pinned as an ARG at the top of the Dockerfile:

ComponentVersion
nginx1.30.4
ingress-nginx controllerv1.11.5
ngx_http_websocket_stat_modulev3.0.5

Tag scheme is <controller>-<ws-module>-nginx<nginx>, e.g. 1.11.5-3.0.5-nginx1.30.4. nginx gained its own component because it now moves independently of the controller.

⁠Building locally

docker build --platform linux/amd64 -t chainstack/ingress-nginx:dev .

amd64 only — that is the only architecture published, and the runtime linker path (/etc/ld-musl-x86_64.path) is derived from the build host's architecture.

The build compiles nginx, LuaJIT, ModSecurity and opentelemetry-cpp from source, so expect roughly 20 minutes rather than the ~1 minute the previous single-module build took.

⁠Bumping nginx

./hack-patch-probe.sh 1.31.3      # does upstream's patch set still apply?

Run this first. It answers in ~30s what a full build takes ~20min to reveal. Then edit ARG NGINX_VERSION in the Dockerfile.

If a patch fails, check whether it is still needed before rebasing it — several are backports of fixes that newer nginx already contains upstream (28_*CVE-2025-23419* is one, on the v1.13.0 tree).

⁠Releasing

Docker Hub autobuild is wired to this repository: merging to master rebuilds latest, and creating a release tagged vX publishes Docker tag X (the leading v is stripped). No manual docker push is involved.

⁠Gotchas when testing

nginx -t fails as www-data with open() "/run/nginx.pid" failed (13: Permission denied). Pre-existing, and harmless in production because the controller renders its own pid path. Add pid /tmp/test.pid; to throwaway test configs.

ws_log_format accepts only this module's own variables ($ws_opcode, $ws_payload_size, $ws_message_size, $ws_packet_source, $ws_conn_age). Putting a standard nginx variable such as $uri or $status in it crashes the worker with SIGSEGV — the module does not validate the format string.

Tag summary

Content type

Image

Digest

sha256:6aa458f29…

Size

101.3 MB

Last updated

19 days ago

docker pull chainstack/ingress-nginx