yum upgrades for production use, this is the repository for you.
Active subscription is required.
Technical Briefing: Native ACME Support in NGINX via nginx-module-acme
The Problem
SSL certificate renewal for NGINX has traditionally depended on external tooling — Certbot, cron jobs, Python dependencies, and deploy hooks. That pipeline is a separate moving part from the web server itself, and it has to be maintained alongside it.
The Fix
NGINX now has a native ACME module (nginx-module-acme) that lets NGINX itself speak ACMEv2 to Let’s Encrypt. Certbot, cron jobs, Python dependencies, and deploy hooks are eliminated from the SSL renewal pipeline.
How It Works
The module runs inside the NGINX worker process. It handles the ACME challenge, obtains the certificate, stores it in shared memory, and renews automatically.
Certificates are exposed via two runtime variables — $acme_certificate and $acme_certificate_key — which you assign to ssl_certificate and ssl_certificate_key. This allows transparent zero-downtime renewal.
Challenge Support
- Supports
http-01andtls-alpn-01. - Does not support
dns-01. This means no wildcard certificates and no certs for hosts unreachable on ports 80/443. For those cases, Certbot remains the right tool.
Installation
The module ships as a prebuilt dynamic module from the GetPageSpeed Premium Repository — no compilation required.
On RHEL:
dnf install nginx-module-acme
Then add at the top of nginx.conf:
load_module modules/ngx_http_acme_module.so;
On Debian/Ubuntu: the package handles module loading automatically — no load_module directive needed.
Configuration Structure
Three parts:
- An
acme_shared_zone(defaultngx_acme_shared:256k). - An
acme_issuerblock (withuri,contact,state_path,accept_terms_of_service). - One or more
serverblocks referencing the issuer viaacme_certificate.
Key Directives
acme_shared_zone zone=name:size— http context.acme_issuer name { ... }— http context. Sub-directives include:uriaccount_key alg[:size] | filechallengecontactaccept_terms_of_servicessl_verify on|offssl_trusted_certificatestate_pathprofilepreferred_chaincommon_name_in_csrexternal_account_key(for CAs like ZeroSSL)
acme_certificate issuer [identifier ...] [key=alg[:size]]— server context.
Operational Notes
- A
resolverdirective is required in the http block. - Both
listen 80;andlisten [::]:80;are needed, since validation may arrive over IPv6. - The
http-01challenge is served automatically under/.well-known/acme-challenge/— no location block required.
Testing Guidance
Use the Let’s Encrypt staging endpoint before production to avoid exhausting strict production rate limits:
https://acme-staging-v02.api.letsencrypt.org/directory
Verify with openssl s_client and nginx -t before reloading.
Security Caveats
- Keep
ssl_verify onagainst public CAs. - Protect
state_path— owned by the NGINX user, never web-served. - Keep
contactset as a backstop for expiry warnings.
Troubleshooting
Common errors include:
directory update failed (connection refused)— check resolver and, on SELinux, runsetsebool -P httpd_can_network_connect 1.- Challenge connection refused on port 80 — check IPv4/IPv6 listeners and firewall.
unsupported challenge: dns-01.- TLS handshake failures from mismatched issuer references.
Performance
There is no per-request overhead — provisioning and renewal happen out of band. Size the shared memory zone up if provisioning dozens of hostnames from one instance.
Availability
The module is open source (reviewable at nginx/nginx-acme) and available now via the GetPageSpeed Premium Repository, which bundles 100+ NGINX modules with automatic updates.
Read the full article: NGINX ACME Module: Let’s Encrypt SSL Without Certbot
