Skip to content

FEATURE: Add Let's Encrypt template using the nginx ACME module#1053

Draft
xfalcox wants to merge 1 commit into
mainfrom
feature/letsencrypt-nginx-module
Draft

FEATURE: Add Let's Encrypt template using the nginx ACME module#1053
xfalcox wants to merge 1 commit into
mainfrom
feature/letsencrypt-nginx-module

Conversation

@xfalcox
Copy link
Copy Markdown
Member

@xfalcox xfalcox commented May 11, 2026

Summary

  • Adds a new templates/web.letsencrypt-nginx.ssl.template.yml as an alternative to the existing web.letsencrypt.ssl.template.yml. It uses the nginx ACME module for native Let's Encrypt support — no acme.sh download, no configure-letsencrypt/letsencrypt shell scripts, no separate port 80 nginx config for HTTP-01 validation.
  • Adds the nginx/nginx-acme module to the base image build (image/base/install-nginx) so the directives are available out of the box.
  • The existing web.letsencrypt.ssl.template.yml (acme.sh) remains and is unchanged; users opt in to the new template explicitly.

How it works

The new template:

  • Writes /etc/nginx/conf.d/letsencrypt-acme.conf at the http level with resolver, acme_issuer letsencrypt { ... }, and acme_shared_zone.
  • Overwrites outlets/server/20-https.conf with acme_certificate letsencrypt; plus ssl_certificate $acme_certificate; / ssl_certificate_key $acme_certificate_key; so the cert paths come from the module's runtime state instead of /shared/ssl/.
  • LETSENCRYPT_ACCOUNT_EMAIL is optional. If set, it is passed as a contact mailto: line in the issuer config.

HTTP-01 challenges work without any extra location config: the module registers its challenge handler at NGX_HTTP_POST_READ_PHASE, which runs before location matching and before the existing location ~ /.well-known block in web.ssl.template.yml can take effect.

Test plan

  • Rebuild base image (image/base) and confirm nginx builds successfully with --add-module=/tmp/nginx-acme (requires Rust toolchain in the parent discourse/ruby image — assumed present from YJIT; verify on first build).
  • Bring up an app container with web.letsencrypt-nginx.ssl in templates: and a real DISCOURSE_HOSTNAME pointing to the host.
  • Confirm certificate is issued on first request and that /shared/letsencrypt-nginx contains the persisted account/issuer state.
  • Confirm force_https is appended to /var/www/discourse/config/discourse.conf.
  • Confirm renewal works after the cert nears expiry (the module auto-renews; no cron needed).
  • Run the existing acme.sh template side-by-side to confirm it is not regressed.

Adds a new web.letsencrypt-nginx.ssl template as an alternative to the
existing acme.sh-based one. The nginx ACME module (built into the base
image alongside ngx_brotli) handles certificate issuance and renewal
natively via http-level directives, removing the need for the acme.sh
download and the configure-letsencrypt/letsencrypt shell scripts.

The existing web.letsencrypt.ssl template remains the default so current
setups are unaffected.
@xfalcox xfalcox force-pushed the feature/letsencrypt-nginx-module branch from b4e8e85 to ccb111a Compare May 11, 2026 18:52
@xfalcox xfalcox marked this pull request as draft May 11, 2026 20:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant