GetPageSpeed Extras

nginx-mod-ech

How to install nginx-mod-ech in CentOS/RHEL 10 (aarch64)

Encrypted Client Hello key management for NGINX-MOD

License: BSD Vendor: GetPageSpeed LLC https://www.getpagespeed.com/server-setup/nginx-mod-a-better-faster-nginx-build

Install

sudo dnf -y install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --enable getpagespeed-extras-nginx-mod
sudo dnf -y install nginx-mod-ech

Description

Key generation and rotation for Encrypted Client Hello (ECH, RFC 9849). nginx reads ECH keys while parsing its configuration, so a new key only takes effect on reload, and a client that picked up an older ECHConfigList from a cached HTTPS DNS record still needs the key it encrypted to. nginx handles that by accepting several ssl_ech_file directives: the first is advertised in retry-configs, the rest stay loaded for decryption only. This package ships nginx-ech-keygen, which maintains that rolling set under /etc/nginx/ech and regenerates the include listing them, plus a systemd timer that rotates on a schedule, plus nginx-ech-publish, which republishes the rotated ECHConfigList in the HTTPS DNS record through provider drop-in scripts (Cloudflare shipped; more under /usr/libexec/nginx-ech-publish). The timer is not enabled on install and nothing happens until you configure it. Set ECH_PUBLIC_NAME in /etc/sysconfig/nginx-ech-rotate, run "nginx-ech-keygen --init", publish the value it prints in the HTTPS record for your ECH-enabled names, then "systemctl enable --now nginx-ech-rotate.timer". Set a provider in /etc/sysconfig/nginx-ech-publish and that record is republished automatically after every rotation. ECH only helps if the HTTPS record is served from a DNS-only zone and clients resolve over DoH. See https://nginx-extras.getpagespeed.com/ech/

Architecture

Optimized for aarch64 (ARM64) architecture. It can be used on AWS Graviton instances, as well as Raspberry Pi 4 and newer.

Compatibility

This package is compatible with all RHEL-based distributions, including CentOS, AlmaLinux, Oracle Linux, Rocky Linux, etc.

RPMs

Package Size Built Changes
nginx-mod-ech-1.30.5-71.el10.gps.aarch64 35 KiB 2026-10-12 Danila Vershinin
- SELinux: allow httpd_t self:process setrlimit (nginx-gps 1.3). With · worker_rlimit_nofile set, every spawned worker (start, reload, binary · upgrade) failed setrlimit(RLIMIT_NOFILE) under the stock policy unless · httpd_setrlimit was enabled, logging one alert per worker and silently · keeping the inherited 1024 soft limit - below worker_connections, risking · EMFILE under load. The denial is dontaudited upstream, so no AVC ever · surfaced.
nginx-mod-ech-1.30.5-70.el10.gps.aarch64 34 KiB 2026-10-12 Danila Vershinin
- SELinux: %post no longer rebuilds the policy store on every update. · semodule -i and semanage port -a/-m each recompile and commit the whole · targeted policy, and neither skips unchanged input, so every package · update paid up to two fsync-heavy commits for nothing (stalled in D-state · for minutes on an I/O-starved VPS). The nginx-gps module is now reinstalled · only when the shipped CIL's sha256 differs from the one recorded at the · last successful install (/var/lib/nginx-gps.cil.sha256) or the module is · missing; the udp/443 http_port_t label is committed only when a read-only · "semanage port -l" shows it absent (never on EL10, where base policy has · it). Failure warnings on stderr are kept.
nginx-mod-ech-1.30.5-69.el10.gps.aarch64 34 KiB 2026-10-12 Danila Vershinin
- QUIC BPF: survive binary upgrade FROM a pre-#1756 binary (<= 1.30.5-67). · The old binary hands over NGINX_BPF_MAPS in its legacy format; upstream's · parser refuses it and the new master exits, silently stranding the old · binary after a package update (observed on web.getpagespeed.com upgrading · 67 -> 68 with "quic_bpf on"). Now the incompatible variable is ignored · with a warning and the new binary starts with fresh BPF state; established · QUIC connections of the previous binary take the same one-time hit a · reload under the old binary already inflicted.
nginx-mod-ech-1.30.5-68.el10.gps.aarch64 33 KiB 2026-10-12 Danila Vershinin
- QUIC: established HTTP/3 connections now survive reload and binary upgrade · (backport of upstream nginx PR #1756, slated for 1.31.7; commits ce6e7d6c1, · 63af971a1, b86259604). With "quic_bpf on", established connections move to · per-worker sockets while listeners take only new connections, so a reload · no longer silently blackholes in-flight HTTP/3 traffic until the client's · idle timeout (reproduced on web.getpagespeed.com 2026-10-12: requests on a · persistent connection stalled 25s to ERR_IDLE_CLOSE after every reload). · - Drop quic_bpf_reload_fix.patch: superseded by the backport. It fixed NEW · post-reload connections but caused the in-flight blackhole by closing the · retiring worker's QUIC socket. · - ABI: the backport's new ngx_event_s "quic" bitfield is repositioned AFTER · cancelable (upstream puts it before), keeping every stock flag at its · stock bit position so dynamic modules compiled against stock 1.30.5 · headers (lua sets ev->cancelable on timers) keep working unmodified. · - Tests: quic_bpf_reload runtime stub replaced with a real in-flight reload · test (persistent HTTP/3 connection across reload must not stall); skips · on lanes without an HTTP/3-capable curl or BPF privileges.
nginx-mod-ech-1.30.5-67.el10.gps.aarch64 32 KiB 2026-09-17 Danila Vershinin
- SELinux: allow httpd_t setattr on /dev/null (nginx-gps policy 1.2). With · the common "error_log /dev/null;" idiom, every logrotate USR1 log reopen · produced a daily [emerg] "chown(/dev/null) failed (13: Permission denied)" · because the master chowns error logs to the worker UID and the stock · policy denies it silently (dontaudit, no AVC). · - SELinux: ship nginx-gps as version-agnostic CIL text instead of a binary · .pp. The .pp module format tracks the build chroot's checkpolicy (3.10 · emits format 24), which targets one userland update behind (libsepol 3.9, · reads 4-23) cannot parse — the module then silently failed to install. · - SELinux: %post now emits a warning to stderr when the nginx-gps module · fails to install instead of swallowing the error.
nginx-mod-ech-1.30.5-66.el10.gps.aarch64 31 KiB 2026-09-16 Danila Vershinin
- SELinux: support "quic_bpf on;" (QUIC connection migration) behind a new · default-off boolean. The stock policy grants httpd_t nothing on the bpf · class, so enabling quic_bpf made nginx refuse to start with "failed to · create BPF map (13: Permission denied)". nginx-gps policy module 1.1 adds · the empirically-captured allows (bpf map/prog permissions plus the bpf, · perfmon and net_admin capability checks), all gated behind the boolean · nginx_quic_bpf, off by default: nothing changes for any install until · "setsebool -P nginx_quic_bpf 1". Verified on Rocky Linux 10 enforcing: · start, reload, binary upgrade and HTTP/3 traffic all clean with zero AVCs; · with the boolean off, behavior is exactly as before.
nginx-mod-ech-1.30.4-66.el10.gps.aarch64 31 KiB 2026-09-09 Danila Vershinin
- SELinux: support "quic_bpf on;" (QUIC connection migration) behind a new · default-off boolean. The stock policy grants httpd_t nothing on the bpf · class, so enabling quic_bpf made nginx refuse to start with "failed to · create BPF map (13: Permission denied)". nginx-gps policy module 1.1 adds · the empirically-captured allows (bpf map/prog permissions plus the bpf, · perfmon and net_admin capability checks), all gated behind the boolean · nginx_quic_bpf, off by default: nothing changes for any install until · "setsebool -P nginx_quic_bpf 1". Verified on Rocky Linux 10 enforcing: · start, reload, binary upgrade and HTTP/3 traffic all clean with zero AVCs; · with the boolean off, behavior is exactly as before.
nginx-mod-ech-1.30.4-65.el10.gps.aarch64 30 KiB 2026-09-07 Danila Vershinin
- gps-license module 1.9.1: fix CLOSE-WAIT connection leak. Every identity · probe request and every hard-enforcement 503 left one worker connection · un-finalized (CLOSE-WAIT) until worker_connections exhausted - a 1/min · monitoring probe could take a server down in about a day (reported by an · Ultra subscriber with a clean 20-probes = +20 CLOSE-WAIT repro). Both · paths now finalize the request; hard 503s appear in access_log, probe · requests remain unlogged. Regression-tested (integration + EL9 e2e with · the reporter's exact ss check) and E2E-proven against production. · - tests: harden the limit_req nano-units equivalence check against slow · builders (issue the whole burst window from one curl process); it · failed 3/3 retries on el10-aarch64 in the Release 64 build, which this · Release 65 supersedes. Also fix the changelog weekday.
nginx-mod-ech-1.30.4-63.el10.gps.aarch64 29 KiB 2026-09-03 Danila Vershinin
- gps-license 1.9.0 tarball refresh: fix Linux compilation of the module's · unit-test harness (POSIX feature-test macro, test path buffer); shipped · module code unchanged. Supersedes the partially-published Release 62 · (x86_64-only, cancelled mid-build) so all architectures converge on the · E2E-proven build (verified against production: beacon machine identity · row landed in repo_license_usage)

Subscribe