You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
What changed
Fixed
A release counts the git tags as taken build numbers, next to the package tags, and never
attaches to an existing tag. Deleting the old nginx-geoip package had made the counter
reuse 1.31.6-1.
The nginx error log kept its own timestamp, although the README says the log filter replaces it. nginx writes the error log to stderr, and the entrypoint filtered stdout only. The entrypoint now points the image link /var/log/nginx/error.log at a second pipe of the filter, and the filtered lines stay on stderr. nginx remains PID 1, and stdout, signals and exit codes do not change. A fatal start error still goes to stderr unfiltered, so it cannot get lost. New tests cover the default error log and a configuration error at start.
Changed
No test reaches the internet. The logrotate and UptimeRobot suites started some containers with the license key test, so they sent a real request to MaxMind and fetched the real UptimeRobot list. All their containers now use the fake curl with a dummy key. It answers 401 by default and passes file:// and localhost URLs to the real curl.
Release notes summarize the release for people instead of listing the commits. They start with the rebuild reason or the nginx update, then the CHANGELOG entries added since the previous release of the branch, then a table of nginx, the base image and the GeoIP2 module with their digests. The commits follow in a collapsed block. .github/scripts/release-notes.sh writes them.
The weekly rebuild names each Trivy finding it fixes in the release notes: CVE, package, installed and fixed version.
The nginx base image is pinned by the digest of its multi-arch index. nginx-branches.env holds nginx:<version>-trixie@sha256:<digest> per branch, the Dockerfile takes it in NGINX_IMAGE and derives the nginx version from the tag. Renovate updates the tag and the digest, so each base change goes through a PR and CI.
The lint job checks that the nginx image and the GeoIP2 module of each branch hold the same nginx version. A Renovate PR that moves nginx stays red until the module for it exists and joins the PR. Before, Renovate read the nginx version from the module image tags.
The Release workflow records the pinned base digest and no longer resolves the upstream tag. The Rebuild workflow compares the org.opencontainers.image.base.digest label with the pinned digest in nginx-branches.env.
Renovate takes its common rules from the shared preset github>intechcore/renovate-config.
The shared preset also turns on OSV vulnerability alerts.
Renovate drops the ghcr.io host rule, because the images are public now.
Added
Line coverage of the scripts. The Dockerfile target coverage records a bash trace per script run, tests/coverage.sh runs the three suites against it and converts the traces with kcov. The new sonar CI job sends the report to SonarCloud for mainline. make coverage runs it locally. The published image does not change.
Tests for the paths the suites did not reach: a new tests/geoip/test-geoip.sh suite for the GeoIP updater (install from an archive, cron wrapper, HTTP error, truncated archive, archive without the database, missing key, download on a cold start), and in the other suites a failed UptimeRobot download, a too short response, a failing nginx -t, a failed initial fetch, a failed rotation and the error_log timestamp of the log filter. tests/fake-bin/curl stands in for curl, so no test reaches MaxMind or UptimeRobot for these paths. Script coverage rises from 82.3% to 100%. The entrypoint runs its two background jobs as functions instead of subshells, and update-uptimerobot.sh renders the geo block with one sed instead of a read loop, so every line shows in the trace. The output stays byte for byte the same.
tests/contract.sh checks that every variable in the README table appears in a test suite. The lint job runs it. New tests cover GEOIP_DIR, UPTIMEROBOT_ENABLED, UPTIMEROBOT_UPDATE_CRON, the LOGROTATE_* settings as the entrypoint renders them, and the scheduled GeoIP job.
Build provenance and SBOM attestations for every release, checked with gh attestation verify. OpenSSF Scorecard workflow and README badges. arm64 builds and tests run on native runners instead of QEMU.
This commit was created on GitHub.com and signed with GitHub’s verified signature.
What changed
Upstream
Moves nginx from 1.30.0 to 1.30.5.
Fixed
A release counts the git tags as taken build numbers, next to the package tags, and never
attaches to an existing tag. Deleting the old nginx-geoip package had made the counter
reuse 1.31.6-1.
The nginx error log kept its own timestamp, although the README says the log filter replaces it. nginx writes the error log to stderr, and the entrypoint filtered stdout only. The entrypoint now points the image link /var/log/nginx/error.log at a second pipe of the filter, and the filtered lines stay on stderr. nginx remains PID 1, and stdout, signals and exit codes do not change. A fatal start error still goes to stderr unfiltered, so it cannot get lost. New tests cover the default error log and a configuration error at start.
Changed
No test reaches the internet. The logrotate and UptimeRobot suites started some containers with the license key test, so they sent a real request to MaxMind and fetched the real UptimeRobot list. All their containers now use the fake curl with a dummy key. It answers 401 by default and passes file:// and localhost URLs to the real curl.
Release notes summarize the release for people instead of listing the commits. They start with the rebuild reason or the nginx update, then the CHANGELOG entries added since the previous release of the branch, then a table of nginx, the base image and the GeoIP2 module with their digests. The commits follow in a collapsed block. .github/scripts/release-notes.sh writes them.
The weekly rebuild names each Trivy finding it fixes in the release notes: CVE, package, installed and fixed version.
The nginx base image is pinned by the digest of its multi-arch index. nginx-branches.env holds nginx:<version>-trixie@sha256:<digest> per branch, the Dockerfile takes it in NGINX_IMAGE and derives the nginx version from the tag. Renovate updates the tag and the digest, so each base change goes through a PR and CI.
The lint job checks that the nginx image and the GeoIP2 module of each branch hold the same nginx version. A Renovate PR that moves nginx stays red until the module for it exists and joins the PR. Before, Renovate read the nginx version from the module image tags.
The Release workflow records the pinned base digest and no longer resolves the upstream tag. The Rebuild workflow compares the org.opencontainers.image.base.digest label with the pinned digest in nginx-branches.env.
Renovate takes its common rules from the shared preset github>intechcore/renovate-config.
The shared preset also turns on OSV vulnerability alerts.
Renovate drops the ghcr.io host rule, because the images are public now.
Added
Line coverage of the scripts. The Dockerfile target coverage records a bash trace per script run, tests/coverage.sh runs the three suites against it and converts the traces with kcov. The new sonar CI job sends the report to SonarCloud for mainline. make coverage runs it locally. The published image does not change.
Tests for the paths the suites did not reach: a new tests/geoip/test-geoip.sh suite for the GeoIP updater (install from an archive, cron wrapper, HTTP error, truncated archive, archive without the database, missing key, download on a cold start), and in the other suites a failed UptimeRobot download, a too short response, a failing nginx -t, a failed initial fetch, a failed rotation and the error_log timestamp of the log filter. tests/fake-bin/curl stands in for curl, so no test reaches MaxMind or UptimeRobot for these paths. Script coverage rises from 82.3% to 100%. The entrypoint runs its two background jobs as functions instead of subshells, and update-uptimerobot.sh renders the geo block with one sed instead of a read loop, so every line shows in the trace. The output stays byte for byte the same.
tests/contract.sh checks that every variable in the README table appears in a test suite. The lint job runs it. New tests cover GEOIP_DIR, UPTIMEROBOT_ENABLED, UPTIMEROBOT_UPDATE_CRON, the LOGROTATE_* settings as the entrypoint renders them, and the scheduled GeoIP job.
Build provenance and SBOM attestations for every release, checked with gh attestation verify. OpenSSF Scorecard workflow and README badges. arm64 builds and tests run on native runners instead of QEMU.
Changed
Renamed from nginx-geoip to nginx-geoip2. New images go to ghcr.io/intechcore/nginx-geoip2. The old package ghcr.io/intechcore/nginx-geoip keeps all its tags and gets no new builds. Build numbers continue: the first build under the new name is 1.31.6-3.
Added
SECURITY.md, CONTRIBUTING.md and .editorconfig. OCI label vendor. The Release workflow passes the commit and the build time, so revision and created are set in published images.
Images for both nginx branches. Mainline keeps latest and gets mainline, stable gets stable. nginx-branches.env holds the nginx version and module of each branch. The Release workflow asks for the branch. CI and the security scan build both branches, Rebuild checks both.
Rebuild also releases when the GeoIP2 module changed. The image carries the module reference in the io.intechcore.geoip2-module label.
Changed
One ci.yml replaces docker-publish.yml, lint.yml and security.yml. Lint adds actionlint, zizmor and trivy config. Tests run on amd64 and arm64. Trivy fails on CRITICAL and reports HIGH to a tracking issue. All workflows set their token permissions and keep no credentials in the checkout. Releases are created with gh release create.
The Release workflow builds and tests each architecture on its own job and pushes exactly the tested image by digest. The publish job joins both into the multi-arch image and creates the tags and the release. Before, the tested amd64 image and the pushed image were two separate builds, and arm64 was not tested at all. All three test suites run.
The Dockerfile ARGs NGINX_VERSION and GEOIP2_MODULE default to mainline. A build without arguments no longer warns about an empty base image name.
The GeoIP2 module comes from ghcr.io/intechcore/ngx_http_geoip2_module:<nginx>-<n>, pinned by digest, instead of a build of leev/ngx_http_geoip2_module HEAD. The fork carries the auto_reload fixes from upstream PR #138 and tests them. The build stage is gone.
Renovate takes the nginx version from the module image tags. The nginx version moves only when a module for it exists, in one PR with the module image.
Added
Weekly Rebuild workflow. It releases the next revision when the upstream nginx:<version>-trixie image was rebuilt under the same tag, or when Trivy finds fixable CRITICAL or HIGH vulnerabilities in the published image. New labels org.opencontainers.image.base.{name,digest} record the base image.
UptimeRobot IP-list auto-updater. A new periodic job, scheduled through the same supercronic instance, fetches the official UptimeRobot monitoring IPs from https://uptimerobot.com/inc/files/ips/IPv4andIPv6.txt and renders an nginx geo $is_uptimerobot { … } block at /etc/nginx/uptimerobot/uptimerobot.map.conf. The file is intended to be included from your http {} block so vhosts can do if ($is_uptimerobot = 1) { … }. A baseline shipped in the image (default 0; only) is installed synchronously on cold volumes so nginx always starts with a valid file. The initial fetch is asynchronous — backgrounded so a slow TLS handshake (e.g. CI QEMU emulation) cannot stretch container startup past docker stop's grace window. Failure policy is fail-open: the existing/baseline file is preserved on download or parse failures, and the cron job retries. On successful rerender, nginx -t is run first and nginx -s reload is signalled only if the content changed (sha256 diff). New env vars: UPTIMEROBOT_ENABLED=true, UPTIMEROBOT_UPDATE_CRON="15 4 * * *", UPTIMEROBOT_DIR=/etc/nginx/uptimerobot, UPTIMEROBOT_URL=https://uptimerobot.com/inc/files/ips/IPv4andIPv6.txt. New 8-test suite at tests/uptimerobot/test-uptimerobot.sh covers baseline validity, happy-path render, nginx -t consumption, idempotency, change detection, and fail-open on garbage upstream.
Fixed
Image no longer ships systemd. Debian 13.7 ships logrotate with Depends: cron | anacron | cron-daemon | systemd-sysv, and apt resolved the first alternative, pulling cron, cron-daemon-common, systemd, libapparmor1 and adduser into the runtime image — an init system nothing starts, since supercronic invokes logrotate directly. The apt layer grew by ~20 MiB and pushed the linux/arm64 build to 253 MiB, past the 250 MiB threshold asserted by logrotate test 22, which failed every PR built after 2026-09-03. anacron is now named explicitly in the install list so the same dependency is satisfied with 3 packages instead of 9.