Skip to content

fix(server): re-enable ACME certificate acquisition - #28

Merged
klobucar merged 1 commit into
mainfrom
jk.acme-fixes
Aug 16, 2026
Merged

klobucar merged 1 commit into
mainfrom
jk.acme-fixes

Conversation

@klobucar

Copy link
Copy Markdown
Owner

What this changes

Re-enables automated Let's Encrypt (ACME) certificate acquisition in the server,
restoring the intended TLS source priority: explicit cert/key files → ACME →
self-signed fallback. Also makes the Let's Encrypt production directory the
explicit default when no custom directory URL is configured, and unpins the
staging URL from fly.toml.

Why

The ACME path was hard-bypassed because rustls-acme 0.15.1 failed to parse
Let's Encrypt's challenge JSON (missing field token), leaving every deployment
on a self-signed cert. Upstream fixed the deserialization for token-less
challenge types in 0.15.2, and our lockfile already carries 0.15.4, so the
bypass is no longer needed (the Cargo.toml requirement is raised to match).

Two footguns fixed along the way:

  • The standalone health-check listener now starts only in non-ACME m
    configure_acme already serves the HTTP-01 challenge route plus a
    check on acme_bind_port, so both would race to bind the same port.
  • rustls-acme's builder defaults to the Let's Encrypt staging directory,
    whose certificates clients don't trust. An unset AURA_ACME_DIRECTORY_URL
    now explicitly selects production instead of silently issuing stag

How tested

  • End-to-end against a live Pebble ACME server
    (test_acme_certificate_acquisition_with_pebble): certificate acquired in
    ~1.2s. Pebble runs from ghcr.io/letsencrypt/pebble (the Docker Hub image is
    no longer pullable).
  • cargo test --workspace, cargo fmt --all -- --check, and
    cargo clippy --workspace --all-targets -- -D warnings all pass.
  • rustls-acme 0.15.4 vetted via Socket (clean scores) and the #[serde(default)]
    token fix confirmed present in the published crate source.

Notes for the reviewer

  • No wire-format or crypto changes — the QUIC ALPN (aura-dave) and
    are untouched; only the TLS certificate source changes.
  • Deployments still inject the real AURA_ACME_DOMAIN / AURA_ACME_CONTACT
    via fly secrets set; the placeholders in fly.toml are unchange
  • First deploy after this merges will request a real certificate from Let's
    Encrypt production — mind the rate limits if redeploying repeatedly.

Checklist

  • Commit messages follow Conventional Commits
  • Commits are signed off (git commit -s) per the DCO
  • cargo fmt --all clean
  • cargo clippy --workspace --all-targets -- -D warnings clean
  • cargo test --workspace passes
  • Wire-format / protocol changes have a corresponding update in docs/protocol.md — n/a, no protocol changes
  • Crypto changes have a corresponding update in docs/MLS_SECURIotocol_deviations.md — n/a, TLS cert sourcing only

The ACME path was bypassed because rustls-acme 0.15.1 failed to parse
Let's Encrypt challenge JSON ("missing field token"). That was fixed
upstream in 0.15.2 (challenge deserialization for token-less challenge
types), and the lockfile already carries 0.15.4, so restore the TLS
source priority: explicit cert/key files > ACME > self-signed fallback.

The standalone health-check listener now starts only in non-ACME modes;
configure_acme's Axum server already serves the HTTP-01 challenge route
and a "/" health check on acme_bind_port, and both binding the same
port would fail.

Also select the Let's Encrypt production directory explicitly when no
custom directory URL is configured — rustls-acme's builder defaults to
staging, whose certificates clients don't trust — and drop the staging
pin from fly.toml accordingly.

Verified end-to-end against Pebble (test_acme_certificate_acquisition_
with_pebble): certificate acquired in ~1.2s.

Signed-off-by: Jonathon Klobucar <jonathon.klobucar@gmail.com>
@klobucar
klobucar merged commit 79e5b83 into main Aug 16, 2026
12 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant