Skip to main content

HTTP validation

Validate certificates over plain HTTP with no DNS provider access. The only requirement is that the ACME challenge path on each domain — /.well-known/acme-challenge/* — reaches CertAutoPilot's challenge endpoint. You wire that up once at your edge (gateway / ingress / reverse proxy) as a route; CertAutoPilot itself can stay internal. Issuance is immediate — there is no DNS propagation to wait for.

When to use

  • You have no API access to the domain's DNS (unsupported provider, external registrar, another team owns DNS).
  • You want the fastest issuance path — HTTP-01 validates in seconds, with no propagation delay.
  • The domain is already fronted by a gateway / reverse proxy / load balancer you can add a route to.

Not for: wildcard certificates (*.example.com) — the ACME protocol only allows DNS-01 for wildcards; internal-only domains the CA cannot reach over HTTP.

Setup: route the challenge path to CertAutoPilot

At the edge each domain is served by, add one route that forwards the ACME challenge path to CertAutoPilot's challenge endpoint:

http://<domain>/.well-known/acme-challenge/* → <certautopilot>/.well-known/acme-challenge/*

CertAutoPilot does not need to be exposed to the internet — the edge (which the CA reaches on port 80) forwards the path to CertAutoPilot over your internal network, on whatever port CertAutoPilot listens on. Set the route once per site; it keeps working for every future issuance and renewal, for any number of certificates, with no per-issuance action. Preserve the path (the token is the last path segment).

Examples. A reverse-proxy route (nginx) that forwards, keeping CertAutoPilot internal:

location /.well-known/acme-challenge/ {
proxy_pass http://cap.internal:8181; # CertAutoPilot, not publicly exposed
}

If your edge can only rewrite, not route, a 301 redirect works too (the CA follows it):

location /.well-known/acme-challenge/ {
return 301 http://cap.example.com$request_uri; # must resolve to port 80/443
}

Which edge, which port. The CA's initial validation request always goes to your domain on port 80 — that is RFC 8555, not a CA quirk. So the edge the domain resolves to must accept :80 for this path (serve it directly, or redirect it). If you use a route/proxy, that's all — CertAutoPilot behind it can be on any internal port. If you use a 301 redirect, note the CA follows redirects only to ports 80 or 443, so the redirect target must be on 80/443 (redirecting to https:// is fine — during HTTP-01 the CA does not validate the target's TLS certificate, so a self-signed cert works).

How it works

  1. You issue a certificate with Validation Method → HTTP. No zone or DNS credential is selected.
  2. The worker starts the ACME order; for each domain the CA issues a unique, high-entropy token.
  3. The worker writes each token's key authorization to the shared token store (MongoDB) — this is lego's Present step.
  4. The CA requests http://<domain>/.well-known/acme-challenge/<token>; your edge routes it to CertAutoPilot, whose endpoint answers with the key authorization as text/plain.
  5. The order finalizes, artifacts are stored, distribution triggers — same as any other issuance.
  6. The tokens are deleted immediately after validation (CleanUp); a 24-hour TTL index reaps any orphans left by a crash.

Because the response is looked up by token and every challenge gets its own CA-generated token, any number of certificates — and any number of domains per certificate — can validate concurrently with zero contention: there is no shared file, so nothing to race over.

Operational notes

  • Which instances serve the endpoint: only api / all mode instances serve /.well-known/acme-challenge/*; worker mode presents tokens by writing MongoDB. In a split deployment, route the path to an API instance (or the service in front of them).
  • Bundled deployments already route it: the standalone installer, the Docker Compose stack, and the Helm chart all ship an nginx front-end that proxies /.well-known/acme-challenge/ straight to the backend (ahead of the SPA fallback). You do not need to touch CertAutoPilot's own reverse proxy — just route the path on the edge your domains resolve to.
    • Kubernetes (Helm): the frontend defaults to a NodePort Service, which a public CA cannot reach — front it with a LoadBalancer/Ingress (the same requirement as reaching the dashboard), or route the challenge path to the backend service from your existing gateway. If your pod network uses a CIDR outside RFC1918 (e.g. EKS's 100.64.0.0/10 secondary range, or IPv6), also set config.server.trustedProxies in values so the real CA IP — not the proxy pod IP — is used for rate limiting; otherwise all challenge fetches share one bucket.
  • The endpoint is unauthenticated by design (the CA cannot log in): it serves only live tokens, responds 404 to everything else, validates the token charset before touching the database, and is IP rate-limited.
  • Auto-renew works — unlike manual DNS, HTTP validation is fully automatic, so scheduled renewals and ARI are both supported.
  • Multi-domain certificates validate each SAN separately — every domain in the certificate needs the challenge path routed (or to resolve to an edge that has it).

Which host does the CA talk to? Each domain itself — the CA resolves that exact name's A/AAAA record and fetches port 80 there. The apex/parent domain plays no role: for aaa.example.com the CA connects to whatever aaa.example.com resolves to, and that is the edge that must route the challenge path.

Troubleshooting

  • CA reports NXDOMAIN looking up A/AAAA — the domain has no DNS record at all. HTTP-01 proves control of a live host, so the domain must publicly resolve to an edge (that routes the challenge path) before issuing. For a not-yet-live domain, use DNS validation instead — a TXT record doesn't require the host to exist.
  • CA reports "connection refused / timeout" — the domain's port 80 isn't reachable from the internet, or no edge answers on the IP the domain resolves to.
  • CA reports 404 on the challenge — the challenge path isn't routed to CertAutoPilot (test: curl -i http://<domain>/.well-known/acme-challenge/test should reach CertAutoPilot, which then 404s — that proves the path is wired), or it's routed to a worker-only instance.
  • CA reports "invalid port in redirect" — you used a 301 redirect to a port other than 80/443; redirect to :80/:443, or route the path directly instead.
  • Wildcard rejected at create — expected; use DNS validation for wildcards.

See also