SSH module
The SSH module copies the certificate + private key + chain to a
target host using SCP/SFTP, then runs post-deployment actions
(typically systemctl reload nginx or equivalent). It is
the most-used distribution module and the only one with full
rollback — every file we overwrite is first saved as
.bak, so a rollback restores the exact previous state.
01Overview
- Transport: SSH v2 (SCP for writes).
- Auth: username + password, SSH private key (with or without passphrase), or TLS client certificate.
- Path set: defines where each file goes (cert, key, chain) with ownership + mode.
- Action set: shell commands run after writes, typically to reload the consuming service.
- Rollback: full. Previous cert/key are kept as
<path>.bak; rollback swaps them back and re-runs the action set. - Concurrency: per-target-group batch concurrency is capped by
DistributionSSHMaxConcurrency(Settings → General).
02Prerequisites
- An SSH module credential (key or password) saved under Settings → Distribution → Credentials.
- Target hosts reachable from the backend. The backend's pod or VM must have SSH egress to every target.
- A user account on each target with write permission to the cert/key directories, plus
sudo(NOPASSWD) for the action set if it uses privileged commands. - A path set and an optional action set.
03Create an SSH target
- Settings → Distribution → Targets → New.
- Module type: SSH.
- Hostname + port (default
22). - Username: the account on the remote host.
- Credential: pick the SSH key credential you created.
- Host-key strategy:
- Trust on first use (TOFU) (default) — accept the first host key seen and pin it thereafter.
- Pinned — paste a known-good host key fingerprint. The module refuses to connect if it changes.
- Save → health check runs a connect +
echo ok.
04Path set
A path set defines the files you want CertAutoPilot to write, with ownership and mode. Example for nginx:
/etc/nginx/ssl/{{ .cn }}.crt root:root 0644 <cert+chain>
/etc/nginx/ssl/{{ .cn }}.key root:root 0600 <private key>
/etc/nginx/ssl/{{ .cn }}.ca root:root 0644 <chain only>
{{ .cn }} is a Go template variable
expanded from the cert's common name. You can reference project
variables (Variables)
the same way. Typical practice is one path set per service template
(nginx, haproxy, apache, postgres, dovecot, etc.) and reuse it across
many targets.
05Action set
Actions run over SSH in sequence after every file has been written. Example:
sudo nginx -t
sudo systemctl reload nginx
Use nginx -t-style preflight to fail fast before reloading. A non-zero exit status marks the target as failed and triggers rollback if it's enabled for the distribution.
06Execute a distribution
- On the cert detail page → Distribution tab → Add distribution.
- Pick the SSH module, a target or target group, a path set, and an action set.
- Optionally enable validation endpoints so we confirm the cert is live post-deploy (see Validation).
- Click Dry-run first. The module returns the exact list of files it will write and commands it will execute, per target. Review.
- Execute. Progress shows per target; a green tick means files written + action set returned 0. Red means failure — open the target's log to see whether it was transport (
network), credential (auth), or post-action (validation) failure.
07Rollback
SSH rollback is the gold standard:
- Before any overwrite, the module copies the existing file to
<path>.bak. - On rollback, the module swaps:
<path>becomes<path>.rollback-tmp,<path>.bakbecomes<path>, the temp file is deleted. - The action set re-runs (most services expect a reload after cert change).
Rollback metadata is stored on the distribution
(LastRollbackMeta). The UI surfaces a Rollback
button when this metadata is present.
If a distribution was the first one to put a cert at the configured path (no prior file), rollback will delete the cert rather than restore — there is no .bak to swap in. The service's reload will then fail, which is usually what you want (it surfaces the rollback clearly).
08Troubleshooting
SSH auth fails despite a valid key
Permission issue on the remote side. The user needs write on the path-set directories and passwordless sudo on the action-set commands. Check ~/.ssh/authorized_keys contains the right public key and the sudoers entry is specific enough.
Host key mismatch after a rebuild
You rebuilt the target VM and the host key changed. If you were using TOFU, clear the pinned fingerprint on the target detail page; if pinned, paste the new fingerprint (and verify it out-of-band).
Action set times out
Long-running reload (systemd's default is 90 s). Edit the action set timeout on the distribution; the action will be killed and the target marked failed if it exceeds.