Skip to content

Renew through Let's Encrypt (HTTP-01)

What you'll have at the end: an endpoint renewing through Let's Encrypt with zero DNS work — the Scout on the endpoint answers the CA's challenge on port 80 itself, installs the certificate, reloads the web server, and re-probes. This is the simplest public lane, validated first against Let's Encrypt's staging environment so the first production order runs a path you have already seen succeed.

Prerequisites:

  • The endpoint is visible on Manage with served proof — else do Track a new endpoint first.
  • The endpoint's hostname resolves in public DNS to the host the Scout runs on — Let's Encrypt validates by connecting to it from the internet.
  • Port 80 reachable from the internet on that host (firewall and any cloud security group). The Scout listens on port 80 during the challenge.
  • Port 80 free at renewal time: either nothing serves plain HTTP on the host, or an operator-local pre hook stops the web server (and the deploy hook restarts it) — see Scout → Security. A server that only listens on 443 needs no hooks for this.

Time: 15–20 minutes, including the staging dry run.

Mock values used throughout — substitute your real ones:

Endpoint shop.example.com, served by Scout web-01
Hub https://hub.example.internal
Scout install root /opt/cyphers (data dir /opt/cyphers/data)

Step 1 — Create a staging profile

Settings → Certificate issuance → Renewal Profiles → New Profile.

Field Value Why
Profile Name le-http01-staging Named for what it does.
Contact Email ops@example.com Registers the ACME account. Accounts are keyed by (email, provider, environment) — the staging and production accounts are separate.
Issuer Type Public ACME
Provider Let's Encrypt HTTP-01 is offered on Let's Encrypt only in this phase — the Validation Method select drops the option on any other provider (see Certificate providers → Phase-1 boundary).
Environment Staging Let's Encrypt publishes a real staging directory, so the dry run exercises the identical flow — challenge, install, reload, re-probe — without touching production rate limits.
Validation Method HTTP-01 The point of this guide.
Key Type ECDSA P-384 (recommended) HTTP-01 generates whatever key type the profile names, RSA included — pick what your clients need.
Delivery Mode Scout (installs and reloads locally)

Leave the rest at defaults and click Create Profile.

You should now see the profile in the Renewal Profiles table with issuance HTTP-01 and environment staging. (Field-by-field detail: Hub → Renewal profiles.)

Step 2 — Adopt the endpoint with the staging profile

On Manage, the shop.example.com row (Untracked) offers Adopt. Pick le-http01-staging (staging) in the Renewal profile select — the picker suffixes staging profiles so you can't grab one by accident later — and click Apply.

You should now see the row managed. Nothing has been ordered yet. (Details: Adopt an endpoint.)

Step 3 — Staging dry run: Renew Now

The staging certificate is really installed

A staging renewal is not a simulation: the Scout installs the staging certificate and reloads the web server, and browsers will warn on it until Step 5 replaces it with the production one — Let's Encrypt's staging issuers are not publicly trusted. Run Steps 3–5 in one sitting, or do the dry run on a non-critical endpoint.

Click Renew Now on the row. The Scout now runs the entire ACME flow locally (see Scout → Commands):

  1. Loads or creates a persistent ACME account for the staging environment (/opt/cyphers/data/acme/staging.json; production uses production.json).
  2. Probes the currently-served certificate before running your pre hook, so it can find and later re-point the on-disk paths the web server actually serves from.
  3. Runs the pre hook (if present), listens on port 80, and lets the CA fetch the challenge token. The whole obtain is bounded by a 3-minute timeout — a wedged order fails rather than hanging the Scout.
  4. Installs the result into the managed directory /opt/cyphers/data/certs/shop.example.com/ (fullchain.pem, cert.pem, chain.pem, privkey.pem — the private key is generated locally and never leaves the host), re-pointing any external served paths at it as symlinks.
  5. Runs the deploy hook (your reload), validates the install, and re-probes the served endpoint. Any validation failure rolls the previous certificate back.

You should now see the renewal close within a minute or two: the endpoint's drawer → Renewals tab shows the newest entry as Closed, and the served certificate's issuer name is unmistakably staging (Let's Encrypt's staging intermediates carry (STAGING) in their names). The plumbing — DNS, port 80, hooks, install, reload — is proven.

Step 4 — Switch the profile to Production

Settings → Certificate issuance → Renewal Profiles, open le-http01-staging, change Environment to Production (rename it if you like, e.g. production-le), and click Save Changes.

You should now see the profile listed with environment production. The endpoint keeps the same profile assignment — no re-adoption needed.

Step 5 — Renew Now again: the production certificate

Click Renew Now on the row again. Same flow as Step 3, now against the production directory; the hostname is added to the Hub's ACME domain allowlist automatically on the click.

You should now see the renewal close, this time with a publicly trusted certificate.

Step 6 — Verify the result

The renewal is closed — drawer → Renewals tab: newest entry Closed. A renewal only closes when a probe has observed the endpoint serving the new certificate, not merely when it was issued (see Renewal lanes → Verification closes every lane).

The world sees it — from any other machine:

$ echo | openssl s_client -connect shop.example.com:443 -servername shop.example.com 2>/dev/null | openssl x509 -noout -issuer -enddate
issuer=C=US, O=Let's Encrypt, CN=...
notAfter=...

The row is healthy — back on Manage, after the next observations the row shows the new expiry and no findings. A brief "Waiting on re-check" right after renewal is normal; it clears as soon as both vantages have re-observed the endpoint.

From here, every future renewal is one click — or none: Enable autopilot.


Troubleshooting

What you see Meaning Remedy
Renewal fails quickly, error mentions the HTTP-01 provider / port 80 The Scout could not bind port 80 — something else is listening. Free the port, or add a pre hook that stops the web server (and a deploy hook that starts it). Hooks are operator-local; the Hub cannot ship them.
Renewal fails after up to ~3 minutes with a challenge/validation error Let's Encrypt could not reach port 80 from the internet (firewall, NAT, DNS pointing elsewhere). The 3-minute obtain timeout also catches a wedged order. Fix inbound port 80 / public DNS for the hostname, then Renew Now again.
409 pre-flight refusal: … on the Renew click The pre-flight found a reason this renewal can't succeed or can't take effect — no order was created. Read the named reason and remedy in the refusal; see Scout → Commands, renewal pre-flight.
duplicate_cert_limit_risk finding Let's Encrypt allows 5 identical-name certificates per 7 days. The pre-flight surfaces the shrinking headroom as you approach the limit and refuses a renewal that would go past it — before any order exists. Wait for the 7-day window to roll before renewing again.
Renewal parks in action needed after install The certificate was issued and installed but the reload didn't take (hook failed, or the server still serves the old cert). No re-issue happens — re-issuing can't fix a flaky reload. Fix the reload/hook on the host; the next routine scan observes the new certificate being served and closes the renewal on its own.
Renew refused, Scout reported dark The bound Scout hasn't been seen recently — nothing could run the flow. Check systemctl status cyphers-scout on the host and the Scout's row under Scouts.
You need a wildcard (*.example.com) HTTP-01 cannot issue wildcards, on any CA. Use a DNS-01 validation method — see Renewal lanes.
a renewal is already in progress for this endpoint In-flight dedup — the previous attempt hasn't reached a terminal state. Wait for it to close or fail; check the drawer.