Skip to content

Renew through a paid / third-party CA (with key reuse)

What you'll have at the end: an endpoint renewing through a commercial ACME CA (DigiCert ONE, or any RFC 8555 CA that gave you a directory URL and EAB credentials), with the endpoint's existing private key kept across the renewal and the web server following the new certificate without a config change.

This is the full third-party flow, end to end. If your endpoint does not need to keep its key, the flow is the same minus Steps 6–7 — the renewal just generates a fresh key.

Prerequisites:

  • The endpoint is visible on Manage with served proof — else do Track a new endpoint first.
  • From your CA account team or portal: the ACME directory URL, the EAB key ID, and the EAB HMAC key. These identify your CA account to the ACME endpoint.
  • A check that your domain's DNS doesn't forbid the CA: run dig CAA shop.example.com +short (and the parent zones). No CAA records means any CA may issue; if records exist, one must authorize this CA. The Hub re-checks this before every order, fail-closed.

Time: 30–45 minutes for the first endpoint (subsequent ones reuse Steps 1–3 and take minutes).

Mock values used throughout — substitute your real ones:

Endpoint shop.example.com, Scout web-01, serving from /etc/nginx/ssl/
Hub https://hub.example.internal
CA directory https://acme.example-ca.com/directory
EAB key ID EXAMPLEKID_x9y8z7A6b5C4d3E2f1G0hIjKlMnOpQrS
EAB HMAC key RXhhbXBsZUhtYWNLZXlNb2NrVmFsdWVGb3JEb2NzT25seU5vdFJlYWxLZXlNYXRlcmlhbEF0QWxs

Step 1 — Register the CA as a provider

Settings → Certificate Providers → Add custom provider. Fill in:

Field Value Why
Provider ID example-ca Lowercase slug, letters/digits/hyphens only. Permanent — pick a name you'll recognize in profile dropdowns.
Display name Example CA What the dashboard shows.
Directory URL https://acme.example-ca.com/directory Exactly as the CA gave it. Must be https://.
Staging directory URL (optional) (leave blank) Most commercial ACME endpoints publish no staging directory. Blank means profiles on this provider are production-only — which is correct, not a compromise.
CAA issuer domain example-ca.com The domain this CA tells its customers to put in CAA records. Mandatory: it's what the Hub's fail-closed CAA pre-check compares against.
Requires EAB credentials ✓ Refuses account registration with nothing stored, instead of failing later with a CA error.

Click Add provider.

You should now see the provider in the panel's provider list, with External Account Binding: Required — not set.

Step 2 — Enter the EAB credentials

Still on the provider's detail: the EAB key ID / EAB HMAC key form. Paste both values exactly as issued — no trimming, no re-encoding, no added padding. The HMAC is a base64url string and is stored as that string; the Hub decodes it at signing time. Click Save EAB credentials.

You should now see the EAB state change to Configured (kid EXAMPLEKID_x9y8z7A6b5C4d3E2f1G0hIjKlMnOpQrS). The HMAC is write-only — it is encrypted at rest and never displayed again. A typo'd HMAC is not detected here; it surfaces in Step 8 at account registration, which is free — before any order exists (see the note there).

Step 3 — Create the renewal profile

Settings → Renewal Profiles → New Profile.

Field Value Why
Profile Name example-ca-rsa-reuse Named for what it does.
Contact Email ops@example.com Registers the ACME account (keyed by email + provider + environment).
Issuer Type Public ACME
Provider Example CA The Step-1 row.
Environment Production The only choice on a provider without a staging directory.
Validation Method DNS-01 (Manual TXT) The lane for third-party CAs: EAB and custom directories are Hub-side, which HTTP-01 (Scout-side, Let's Encrypt-only this phase) cannot carry. Manual works even with zero DNS automation — and on a prevalidated CA account there is often no DNS step at all (Step 8).
Key Type RSA 2048 (legacy compatibility) Match the endpoint's existing key — check with openssl rsa -in shop.key -noout -text | head -1. On this lane an RSA type nominates the reused key; it will not generate a fresh RSA key.
Preferred Chain Default (CA decides) The only accepted value off Let's Encrypt.
Delivery Mode Scout (installs and reloads locally)
Key Handling ✓ Reuse private key across renewals (for pins/DANE) The point of this guide. If reuse is impossible the renewal is refused, never silently rotated.
Max Retries 0 Every order on this CA costs money. Zero retries means one attempt per explicit click — a failure stops and tells you, instead of retrying a paid operation on its own.

Click Create Profile. You should now see it in the Renewal Profiles table with issuance DNS-01 (Manual TXT) and env production.

Step 4 — Make the certificate directory visible to the Scout

On the endpoint host, the directory the web server serves from must be in the Scout's cert-dirs file — this is what lets the Scout find the served key (Step 6), adopt it (Step 7), and later re-point the served files at the renewal (Step 9):

$ echo "/etc/nginx/ssl" >> /opt/cyphers/cert-dirs.conf
$ sudo systemctl reload cyphers-scout

You should now see cert-dir file reloaded — starting a scan cycle in journalctl -u cyphers-scout, and within a couple of minutes the endpoint's drawer shows the discovered on-disk certificate.

Step 5 — Adopt the endpoint with the profile

On Manage, the shop.example.com row (Untracked) offers Adopt. Pick example-ca-rsa-reuse in the Renewal profile select and click Apply.

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

Step 6 — First Renew Now: the expected refusal

Click Renew Now. You should see:

pre-flight refusal: key_reuse_adoptable

The Activity feed spells it out: the key this endpoint serves is at /etc/nginx/ssl/shop.key, which the Hub does not manage — reuse can only load a key the Scout itself holds. This refusal is free (no order was created) and it is the design working: the alternative would be silently rotating a key you configured the profile to keep.

Step 7 — Adopt the key

Open the drawer and click Adopt key from /etc/nginx/ssl/shop.key. The Scout verifies the key matches what the endpoint currently serves, then copies it (on the host — it never crosses the network) into its managed storage. Verify yourself:

$ sudo openssl rsa -noout -modulus -in /etc/nginx/ssl/shop.key | openssl sha256
SHA2-256(stdin)= ab12cd34ef56...
$ sudo openssl rsa -noout -modulus -in /opt/cyphers/data/certs/shop.example.com/privkey.pem | openssl sha256
SHA2-256(stdin)= ab12cd34ef56...

Same digest = same key. (Full detail: Adopt a private key.)

Step 8 — Renew Now again — ⚠ this may be the paid click

Where money is spent

On a CA account whose domains are prevalidated (typical for OV/organization-validated setups), the order arrives with nothing left to prove, and the Hub's DNS watchdog finalizes it automatically within ~30 seconds — there is no second confirmation between this click and a billed certificate. Treat Renew Now as the purchase.

Before the order, the first-ever renewal on this provider registers the ACME account — which is free and is where bad EAB credentials fail. The Hub log line Persisted new ACME account credentials marks success; a registration error at this point has cost nothing — re-check Step 2 and click again.

Click Renew Now. Every name the order carries is added to the ACME domain allowlist automatically, the CAA pre-check runs, and the order is created. Two shapes from here:

Shape A — prevalidated (no DNS work). The drawer briefly shows Complete renewal — "No DNS records are required — the CA has already validated every domain on this order." — and the watchdog completes it on its own within about 30 seconds. You'll simply see the renewal close.

Shape B — TXT records required. The drawer shows Add DNS TXT record with the exact record(s):

_acme-challenge.shop.example.com
= ab12cd34ef56gh78...

Publish them in your DNS console. There is no deadline — the order parks until you act, and the Hub re-checks it every 30 seconds, completing the renewal on its own once every authoritative nameserver of your zone serves the records. Verify & Complete just runs that check immediately.

The all-nameservers bar is deliberate: the CA validates against whichever authoritative host it likes, so the Hub refuses to submit for validation — which is one-shot, and burns the order on a wrong answer — until the whole fleet agrees. Right after you edit a record, "still waiting on ns2.example-dns.com" is normal; it clears as your provider's servers converge.

Step 9 — Verify the result

Wait for the renewal to close (Scout install + reload + served re-probe; usually under a minute after finalization), then check each claim:

The renewal is closed — drawer → Renewals tab: the newest entry reads Closed, with Key: reused.

The served files followed — on the host, the external path is now a symlink into the Scout's managed directory, so nginx's unchanged config follows every future renewal:

$ ls -l /etc/nginx/ssl/shop.pem
lrwxrwxrwx ... /etc/nginx/ssl/shop.pem -> /opt/cyphers/data/certs/shop.example.com/fullchain.pem

The original files were quarantined by the deploy transaction, not deleted.

The key never changed:

$ sudo openssl rsa -noout -modulus -in /opt/cyphers/data/certs/shop.example.com/privkey.pem | openssl sha256
SHA2-256(stdin)= ab12cd34ef56...        # identical to Steps 1/7

The world sees the new certificate — from any other machine:

$ echo | openssl s_client -connect shop.example.com:443 -servername shop.example.com 2>/dev/null | openssl x509 -noout -serial -issuer -enddate
serial=04ABCD1234EF...
issuer=CN=Example CA TLS RSA CA G1...
notAfter=Mar  8 12:00:00 2027 GMT

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.


Troubleshooting

What you see Meaning Remedy
pre-flight refusal: key_reuse_adoptable Served key exists but isn't under management. Expected once — Step 7.
pre-flight refusal: key_reuse_key_missing The Scout holds no key and can't see the served one — usually the cert directory isn't in cert-dirs.conf. Do Step 4, wait one cycle, retry.
pre-flight refusal: key_reuse_algo_mismatch Profile key type ≠ held key (e.g. rsa_4096 profile, 2048-bit key). Fix the profile's Key Type to match the real key.
pre-flight refusal: key_reuse_diverged Something else rotated the served key after adoption — another renewer (certbot?) is still active. Stop the other renewer, re-adopt, retry. See Take over certbot.
Provider option flagged — EAB required / issuance blocked on EAB Provider requires EAB, none stored. Step 2.
Renewal fails during account setup, no order created Bad EAB credentials or directory URL — caught at free registration. Re-enter Step 2 values exactly as issued; retry costs nothing.
CAA refusal in pre-flight The domain's CAA records don't authorize this CA (or the provider row's CAA issuer domain is wrong). Fix the CAA record — or the Step-1 field — and retry.
Parked on TXT, then failed after 5 minutes The manual-DNS window lapsed. Order unfinalized — unpaid. Renew again with the records ready.
Renewal parks in action needed after install Certificate issued + installed but the reload didn't take (hook failed or reload ineffective). No re-issue happens. Fix the reload/hook on the host; the next routine scan closes the renewal on its own.
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.