Skip to content

Add automatic certificates through rustls-acme - #205

Merged
abs0luty merged 1 commit into
masterfrom
feature/acme
Nov 10, 2026
Merged

abs0luty merged 1 commit into
masterfrom
feature/acme

Conversation

@abs0luty

@abs0luty abs0luty commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Adds an optional tls-rustls-acme feature and an acme module that obtains and renews certificates automatically through rustls-acme. This covers the request in #113 for Caddy-like automatic HTTPS.

use axum_server::acme::{caches::DirCache, AcmeConfig, Acceptor};
use futures_util::StreamExt;

let mut state = AcmeConfig::new(["example.com"])
    .contact(["mailto:[email protected]"])
    .cache(DirCache::new("./acme-cache"))
    .directory_lets_encrypt(true)
    .state();

let acceptor = Acceptor::new(&state);

tokio::spawn(async move {
    while let Some(event) = state.next().await {
        if let Err(error) = event {
            eprintln!("acme: {error:?}");
        }
    }
});

axum_server::bind(addr)
    .acceptor(acceptor)
    .serve(app.into_make_service())
    .await?;
  • The renewal stream must be polled. The application owns the AcmeState and polls it, as shown above; without the loop no certificate is acquired or renewed. This keeps the library free of hidden background tasks.

  • TLS-ALPN-01 only, so the server must be reachable on port 443. HTTP-01 needs a separate :80 listener and rustls-acme's tower feature; it can be a follow-up.

  • ZeroSSL is not supported: it requires external account binding, which rustls-acme does not implement. Let's Encrypt and other non-EAB ACME CAs work.

  • rustls-acme's own axum feature is not used: it pins axum-server 0.8, which cannot compile against 0.9.

  • The feature enables rustls-acme's aws-lc-rs, tls12, and webpki-roots features, and implies our tls-rustls.

  • Added tls-rustls-acme to the clippy, build, test, and minimal-versions matrices.

  • The minimal-versions job needed a num-bigint lower bound: 0.4.0 does not compile on current rustc (div_ceil now resolves to the inherent method). Pinned in minimal-versions/Cargo.toml like the existing tower-layer and aws-lc-rs pins.

Add the optional `tls-rustls-acme` feature and the `acme` module.
`Acceptor` implements the accept hook with rustls-acme's resolver,
handles TLS-ALPN-01 validation connections, and serves acquired
certificates with h2 and http/1.1 ALPN. The application polls the
`AcmeState` for renewal.

This avoids rustls-acme's own axum adapter, which pins axum-server 0.8.
Includes an example, tests with self-signed configs, and CI wiring.
@abs0luty
abs0luty merged commit 382fbad into master Nov 10, 2026
34 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