How to set up an SSH server and an SSH client by hand. For automated host setup, use the Ansible role instead — it performs the server steps below. Read the concept page first.
Goal: the server presents its own host certificate and trusts user certificates signed by the User CA.
- NTP/chrony running (certificate validity depends on the clock).
- The local accounts your principals map to (e.g.
root,deploy) already exist.
-
Generate the host key on the node (the private key never leaves it), and send only the public key to the operator:
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N "" -q # usually already present cat /etc/ssh/ssh_host_ed25519_key.pub # send THIS to the operator
-
Get the deploy bundle from the operator (the host detail page → Files to place on this server). Place each file at the path shown. It contains:
File Path Mode Host certificate /etc/ssh/ssh_host_ed25519_key-cert.pub0444User CA public key /etc/ssh/ssh-user-ca.pub0444sshd drop-in /etc/ssh/sshd_config.d/60-ssh-ca.conf0644AuthorizedPrincipals (per account) /etc/ssh/auth_principals/<account>0644The drop-in contains:
HostKey /etc/ssh/ssh_host_ed25519_key HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub TrustedUserCAKeys /etc/ssh/ssh-user-ca.pub AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u RevokedKeys /etc/ssh/revoked_keysIf your host key is not ed25519, the bundle already adjusts the
HostKey/HostCertificatepaths to match (e.g.ssh_host_ecdsa_key). -
Set up the KRL file.
RevokedKeysgates user logins, so the server serves the User CA's KRL (revoked user certificates). The file must exist or sshd refuses to start. The bundle's KRL snippet does this:sudo install -m 0444 /dev/null /etc/ssh/revoked_keys # then refresh on a schedule (cron), replacing YOUR-PKI-HOST: */15 * * * * root curl -fsS -o /etc/ssh/revoked_keys.new "https://YOUR-PKI-HOST/krl/<UserCaId>.bin" \ && install -m 0444 -o root -g root /etc/ssh/revoked_keys.new /etc/ssh/revoked_keys
-
Validate and reload (reload, not restart — OpenSSH re-reads the cert, trust anchors, and KRL per authentication):
sudo sshd -t && sudo systemctl reload ssh # unit is "ssh" on Debian/Ubuntu, "sshd" on RHEL
Almost always the principal-in-two-places rule: the principal in the user's
cert is not in this host's /etc/ssh/auth_principals/<account> for the account
they're logging into. Re-check the mapping on the Principals page and that the
file was deployed.
Goal: log in with a User CA-signed certificate instead of copying a public key
into authorized_keys.
-
Have a key (the certificate signs your existing public key):
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 # if you don't have one cat ~/.ssh/id_ed25519.pub # send ONLY this to the operator
-
Save the certificate the operator returns next to your private key, with a matching base name and
-cert.pubsuffix —sshthen presents it automatically:# paste into ~/.ssh/id_ed25519-cert.pub chmod 644 ~/.ssh/id_ed25519-cert.pub
-
(Optional) add a
~/.ssh/configblock (scope theHostpattern to your fleet):Host *.example.com IdentityFile ~/.ssh/id_ed25519 CertificateFile ~/.ssh/id_ed25519-cert.pub IdentitiesOnly yes -
Trust the servers' Host CA so host-key warnings stop — add the Host CA
@cert-authorityline to~/.ssh/known_hosts(the operator provides it, orcurl https://YOUR-PKI-HOST/ssh/cert-authority?pattern=*.example.com). -
Verify and log in:
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub # check principals, validity, options ssh <account>@server.example.com # account must map to one of your principals
When the certificate expires (~1 week), request a fresh one the same way — no new key needed.