Skip to content

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:

  1. The Scout connects to your own service — 127.0.0.1:443 with your domain as SNI — and reads the certificate you are actually serving.
  2. It takes the SHA-256 fingerprint of that certificate.
  3. 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.
  4. 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:

/etc/ssl/wildcard.dogwood.example.pem
    -> /opt/cyphers/data/certs/code.dogwood.example/fullchain.pem

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.pem as the account that used to own it) can no longer read through the link; use sudo. 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.com covers foo.example.com, and does not cover example.com or a.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.