Certificate files: naming, discovery and takeover¶
You do not have to rename, move, or reorganise anything before installing Cyphers. Whatever your certificate files are called today, and wherever your web server reads them from, the Scout finds them and keeps them updated in place.
This page explains how that works, so you can see why no preparation is needed.
Filenames are never used to identify a certificate¶
Certificate files get called all sorts of things. On a server you inherited you
might find cert.pem, fullchain.pem, 1.pem, server.crt,
wildcard.example.com.pem, or a name somebody chose years ago. Private keys are
no more consistent: privkey.pem, mykey.pem, server.key, privkey.key.
Cyphers does not care about any of it. A certificate is identified by its content, never by the name of the file it happens to sit in:
- The Scout connects to your own service —
127.0.0.1:443with your domain as SNI — and reads the certificate you are actually serving. - It takes the SHA-256 fingerprint of that certificate.
- It walks your configured certificate directories, opens every file, decodes every PEM block inside it, and keeps any file containing a certificate whose fingerprint matches.
- It finds the matching private key by comparing public keys, not names.
So a file called 1.pem is treated exactly like a file called fullchain.pem.
A key called mykey.pem is found just as readily as privkey.pem. Nothing is
inferred from a filename, so nothing breaks when a filename is unusual.
This also means the starting point is what you are really serving, not what a config file claims. If your nginx points at one path while a stale copy sits beside it, the served certificate is the one that gets adopted.
Your paths keep working — the server config is not edited¶
Cyphers never rewrites your web server configuration.
When a certificate is renewed, the new material is written into the Scout's own managed directory, and each file your server was already reading is replaced by a symbolic link pointing at the managed copy. Your nginx or Apache keeps reading the exact path it always read; that path now resolves to the file Cyphers maintains.
A real example from a live deployment:
nginx still names /etc/ssl/wildcard.dogwood.example.pem. Nobody edited the vhost.
Renewals land at the other end of the link.
Every copy of the old certificate in a watched directory is taken over, not
only the path your server names. A common layout is a link and the file
behind it side by side — mqtt-chain.pem -> mqtt-fullchain.pem,
mqtt.key -> privkey.pem. Both the link and the regular file it resolves to
are republished: the link so your server reads the new certificate, the file
so no copy of the old certificate or its key is left lying beside it. Only
files inside the directories the Scout is configured to search are touched. A
link that points outside them is repointed, and the file it used to point at
— certbot's own archive/, say — is left exactly as it was.
Three consequences worth knowing:
- A published path is readable by root only. The link belongs to the
Scout, and it points into the Scout's data directory, which is closed to
every other user (
0700) because it also holds the Scout's own identity key. A web server whose master process runs as root — nginx, Apache — reads it exactly as before. A non-root user who could read the original file (ls -l ~/certs/fullchain.pemas the account that used to own it) can no longer read through the link; usesudo. This is deliberate: the managed copy of your private key is never readable by anyone but root, whatever the original file's mode was. A service that reads its certificate as a non-root user cannot follow the link — keep that service's files outside the directories the Scout searches and copy the renewed certificate to them from your deploy hook. - Your reload hook keeps working, because your server's configuration never
changed. The deploy hook is your own script — typically
nginx -t && systemctl reload nginx. - Rollback restores what was there. Every path is snapshotted before it is touched. If the new certificate fails validation or your reload hook rejects it, the previous files are put back exactly as they were and the old certificate stays in service.
Each file keeps the shape it already had¶
A certificate file can hold different things, and which one it holds is part of your server's configuration even when the filename says otherwise:
| What the file holds | What Cyphers publishes there |
|---|---|
| The end-entity certificate only | the end-entity certificate only |
| Certificate + issuer chain (a "fullchain") | certificate + issuer chain |
| The issuer chain only, no certificate | the issuer chain only |
| A private key only | the private key |
The shape is read from the file's contents, not from its name. A chain.pem
that actually holds a fullchain is treated as a fullchain; a fullchain.pem
that actually holds a bare certificate is treated as a bare certificate.
This matters most for the split layout Apache and some nginx setups use:
ssl_certificate /etc/ssl/cert.pem # leaf only
ssl_trusted_certificate /etc/ssl/chain.pem # issuers only
Both files are found and both are updated, each with the right half. The chain file is located by matching your server's issuer chain — it contains no end-entity certificate, so a fingerprint match alone could never see it.
A chain-only file is updated only when it sits in the same folder as one of
the certificate's own files. Every certificate from the same intermediate
has a byte-identical chain file, so a chain.pem in another certificate's
folder (another /etc/letsencrypt/live/<name>/, say) is that certificate's
and is never touched. A chain file alone in a folder, with no certificate
beside it, is never updated either: nothing ties it to one certificate.
What Manage shows¶
Open an endpoint's drawer and look at Known certificates. Under each certificate's Path, Files lists the files in the certificate's own folder that hold its material or its issuer chain — the folder stated once, the filenames under it — each with what the file actually contains, read from the file's contents, never from its name:
| Label | The file holds |
|---|---|
| certificate only | the end-entity certificate alone |
| certificate + chain | the certificate followed by its issuer chain (a "fullchain") |
| issuer chain only | the intermediates, no end-entity certificate — listed when it sits beside the certificate and its issuer matches; a chain file in another certificate's folder is that certificate's, not this one's |
| private key | the certificate's paired key, matched by public key; only the path is shown, and if it lives in another folder that folder is listed too |
| certificate + key in one file | HAProxy-style combined files |
| bundle of N certificates | more than one end-entity certificate in one file |
This is the same set of files a renewal will republish, each with the right
half. Copies under backups/archive/ are history and are not listed. A Scout
older than this feature reports one path, and the drawer shows just that.
What is deliberately refused¶
Adoption is not a grab. The Scout declines to take over a path when:
- The probe fails. If nothing answers on the port, nothing is adopted — guessing from a config file could claim a path the service does not use.
- The served certificate does not cover the domain. Some other TLS service
answering on that port is not yours to replace. Wildcards are understood here:
*.example.comcoversfoo.example.com, and does not coverexample.comora.b.example.com. - No file matches. If the served certificate is not on disk anywhere the Scout is allowed to look, nothing is adopted; the renewal falls back to your deploy hook.
- The path is one of the Scout's own managed artifacts — that is not a target to deploy to, it is the source.
- The file also holds the private key. HAProxy requires this layout, and some nginx setups use it. Replacing such a file with a certificate-only one would destroy the key half and the service would stop starting, so the file is left exactly as it is.
- The file holds more than one end-entity certificate. There is no single correct replacement, so nothing is chosen.
- The file cannot be replaced — its directory is not writable by the Scout.
Nothing is skipped in silence¶
A refused file is a file that will keep serving the old certificate. That is worse than an error if nobody is told, so every case above is reported.
Before a renewal runs, the Hub asks the Scout what it can see and surfaces what it finds as pre-flight findings:
| Finding | Effect |
|---|---|
| A combined certificate-and-key file | Blocks, with "Proceed anyway" available |
| More than one certificate in one file | Blocks, with "Proceed anyway" available |
| A path the Scout cannot write | Blocks, with "Proceed anyway" available |
| Another service's certificate in the managed directory | Refuses outright |
| A file in an encoding we cannot rewrite (DER, PKCS#12) | Notice only |
| A directory that could not be searched | Notice only |
The three blocking cases stay overridable on purpose: if you have a deploy hook that rebuilds the file after renewal, you have a second path to it and may proceed. The collision case is not overridable — the next install would overwrite a certificate that is not ours.
If your layout is a single certificate file plus a key — by far the most common shape — none of the above applies to you.
Related¶
- Adopt an endpoint
- Certificate discovery — how the Scout inventories what is on a host
- Certificates: identity & observation