[feature] Serve precompressed static files#653
Conversation
📝 WalkthroughWalkthroughThis PR adds Brotli static compression support to the Nginx Docker image. The Dockerfile now uses a multi-stage build to compile the ngx_brotli module against a parameterized nginx version and installs it into the runtime image. Nginx configuration templates load the brotli module and update static file serving to use Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant Nginx
participant StaticDir
Client->>Nginx: GET /static/file.css
Nginx->>Nginx: load_module ngx_http_brotli_static_module
Nginx->>StaticDir: check for file.css.br (brotli_static)
StaticDir-->>Nginx: precompressed file or fallback
Nginx-->>Client: response (brotli/gzip/plain)
Related PRs: None identified. Suggested labels: enhancement, nginx, docker Suggested reviewers: nginx/infra maintainers familiar with Docker multi-stage builds and Nginx configuration templates. Poem
Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (2 errors, 2 warnings)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| @@ -1,7 +1,46 @@ | |||
| FROM nginx:1.31.2-alpine | |||
There was a problem hiding this comment.
@coderabbitai wouldn't this cause problems do dependabot?
There was a problem hiding this comment.
🧩 Analysis chain
🤖 web_search executed:
Does Dependabot support updating Docker FROM image version when using a global ARG variable for the tag in multi-stage builds?
Length of output: 9360
🏁 Script executed:
#!/bin/bash
fd -i dependabot .github -a
cat .github/dependabot.yml 2>/dev/nullLength of output: 1238
@nemesifier, good instinct to double-check, but this pattern should actually work fine with Dependabot.
Docker ecosystem is enabled for /images/openwisp_nginx in .github/dependabot.yml, so the Dockerfile is scanned.
The key thing here is that Dependabot added explicit "global ARG" support (dependabot-core#2057, landed via PR #4837) precisely for this pattern: an ARG with a default value declared before the first FROM, then redeclared inside each stage that needs it. That's exactly what this Dockerfile does:
ARG NGINX_VERSION=1.31.2
...
FROM nginx:${NGINX_VERSION}-alpine AS brotli-builder
ARG NGINX_VERSION
...
FROM nginx:${NGINX_VERSION}-alpine
ARG NGINX_VERSIONSince both FROM lines resolve the same NGINX_VERSION variable (not two independently hardcoded tags), Dependabot's parser treats it as a single dependency and only needs to bump the one ARG NGINX_VERSION=1.31.2 line — it won't try to open separate/conflicting PRs for each FROM. That "two FROM directives" problem (dependabot-core#6700) mainly affects Dockerfiles where each FROM hardcodes its own version string independently (e.g., nginx:1.19.9 and nginx:1.19.9-alpine written separately) — that's not the case here since both stages share the same ARG-driven tag.
So, this should be safe — Dependabot will detect the ARG NGINX_VERSION=1.31.2 line and bump it, updating both stages consistently in a single PR.
Summary
Adds support for serving precompressed static assets from the nginx container.
Changes
brotli_staticand movesgzip_staticinto the static file locations.aliaslocations for static files so nginx serves.brand.gzfiles directly instead of compressing the original file at request time./static/custom/mapped separately so documented custom theme assets continue to work.Notes
The Brotli module is built in the image instead of installing Alpine's
nginx-mod-http-brotlipackage because the official nginx image uses nginx.org packages, while Alpine module packages target Alpine's own nginx build.