Getting the data-plane feature you need on the distro you must run
Nginx builds, a ModSecurity artifact and a Lua kit.
One recurring obstruction: the edge feature you need is available in principle and absent from the image you are allowed to run. nginx-lua builds nginx with LuaJIT across six distributions, multi-arch, rebuilt within a day of each upstream release since 2020; nginx-modsecurity ships the module as an artifact rather than another image to adopt; the WAF kit is a kit, not a product. This is the part of the estate with independent external adoption.
The problem
An engineer needs to run a small piece of logic at the edge: rewrite a header based on a lookup, validate a JWT before the request reaches the application, rate-limit by a key the load balancer cannot see. The right place for this is the proxy, and nginx has supported it for over a decade through the LuaJIT module.
The obstruction is not technical. It is distribution.
The official nginx image does not include the Lua module. OpenResty does, and OpenResty is a distribution with its own release cadence — new nginx releases arrive there on OpenResty's schedule rather than nginx's, which matters when the reason you are upgrading is a published CVE. And in a large number of organisations the choice of base distribution is not the engineer's to make: security policy says AlmaLinux, or the platform team standardised on Amazon Linux, or the compliance baseline is built on Ubuntu LTS. "Use OpenResty" resolves the feature and violates the policy.
So the engineer builds nginx from source. This is entirely possible and, in the author's experience, about a week of work, most of it spent discovering that the module needs to be compiled against the exact nginx version, that the build flags must match the official image's configure line or subtle behaviour changes, that the arm64 build has its own problems, and that the whole thing must be repeated on every nginx release, which is roughly monthly and more often when a CVE lands.
ModSecurity has the same shape, worse. The v3 module must be compiled against the target nginx version and the target libc. A module compiled against the wrong one compiles cleanly and fails at startup, which is the most expensive class of build error: it passes CI and breaks in the deployment.
The pattern generalises beyond nginx. Any proxy with an optional module system produces the same shape: a feature that exists upstream, an official image that does not carry it, and an organisation whose distro choice is fixed by something other than engineering preference. The resolution is always somebody's build matrix.
The method
Build the matrix, and publish it explicitly. nginx-lua supports AlmaLinux, Alpine, Amazon Linux, Debian, Fedora and Ubuntu, on amd64 and arm64, with the same build configure line as the official nginx image so behaviour does not drift from what upstream documents. The tag list is generated and maintained in the README, and it encodes the full coordinates; the Alpine row, as of 22 September 2026:
1, 1.31, 1.31.6, alpine, latest, 1-alpine, 1.31-alpine,
1.31.6-alpine, 1-alpine3.24.2, 1.31-alpine3.24.2, 1.31.6-alpine3.24.2
Listing 1 — The tags published for one nginx build on one distro, from the loosest pin to the tightest.
You can pin as loosely as alpine or as tightly as 1.31.6-alpine3.24.2: nginx version, distro and distro version. A team with a compliance requirement on distro patch level can express it in a tag. The cost is the matrix itself: six distros, two architectures and every nginx release is a large number of images to rebuild, scan and sign, and the project gives up the curated, tested-together module set a distribution offers in exchange for not waiting.
Ship the artifact, not the appliance. This is nginx-modsecurity's central decision. It publishes the .so, the libmodsecurity shared library and the Unicode mapping file, as the nginx-modsecurity-module image, for you to copy into your image. The README's snippet:
FROM ghcr.io/fabiocicerchia/nginx-modsecurity-module:3.0.16-nginx1.27.5 AS modsec
FROM nginx:1.27.5
RUN apt-get update \
&& apt-get install -y --no-install-recommends libcurl4 libgeoip1 liblmdb0 libxml2 libyajl2 \
&& rm -rf /var/lib/apt/lists/*
COPY --from=modsec /modules/ngx_http_modsecurity_module.so /usr/lib/nginx/modules/
COPY --from=modsec /lib/ /usr/local/modsecurity/lib/
COPY --from=modsec /conf/unicode.mapping /etc/nginx/modsecurity/unicode.mapping
RUN ldconfig /usr/local/modsecurity/lib
Or without a registry at all: make extract NGINX_VERSION=1.27.5 writes the files to dist/. You keep your base, your version, your config layout and your patch cadence, and gain only the part you could not easily build.
A kit, not a WAF product. nginx-lua-waf-kit is a set of Lua modules (rate limiting, bot scoring, edge JWT validation, geo/ASN policy, request mirroring), each opt-in, versioned tag-for-tag against nginx-lua releases so existing users adopt incrementally rather than migrating. Nothing turns on by default. That framing is the README's own, and it sets the support expectation: these are building blocks you wire up, and examples/waf.conf.example shows the wiring.
Tagged example sets. Because the examples are nginx configuration for a specific nginx-lua release, the newest commit on main does not say which runtime it was written for. Each example set is tagged (git checkout examples/nginx-lua-v1.31.2) and examples/compat.json records which release the current set targets.
The headline results
- The maintenance record.
- The ModSecurity module is tested by loading it.
- The build is verifiable and signed.
- The matrix is a real constraint.
- The WAF kit is tested as Lua, not as configuration.
The full results, with the tables and the reasoning behind each figure, are in the PDF.
What is in the PDF
- The problem — what goes unanswered without it, and who notices first.
- Why the obvious alternative falls short — stated plainly, including where it is the better choice.
- How it works — the method, not a feature list.
- Concrete use cases — with console output quoted from the repository, never reconstructed.
- The methodology behind any number it emits — every term shown, so the figure survives a question.
- What it deliberately does not do — the section most papers leave out.
Part of the catalogue.
Get the PDF
This paper already selected; the download starts when you send the form. No follow-up sequence.