ssh starters, one flag per page
Twenty-eight steps for people who type ssh user@host every day and have never looked underneath: ssh and sshd as two programs, the fingerprint yes and known_hosts, the changed-key warning, ssh-keygen's Ed25519 default, the public and private halves, authorized_keys and ssh-copy-id, the passphrase and the agent, the permissions that silently ignore a key, ~/.ssh/config stanzas, keys-only hardening with sshd -t, the four-step handshake, host key rotation, ServerAliveInterval, the tilde escapes, ProxyJump, -L tunnels, and PerSourcePenalties, one flag per page.
A diagram, the classic trap, and one thing to go try this week. That's a page.
ssh starters, one flag per page
Twenty-eight steps for people who type ssh user@host every day and have never looked underneath: ssh and sshd as two programs, the fingerprint yes and known_hosts, the changed-key warning, ssh-keygen's Ed25519 default, the public and private halves, authorized_keys and ssh-copy-id, the passphrase and the agent, the permissions that silently ignore a key, ~/.ssh/config stanzas, keys-only hardening with sshd -t, the four-step handshake, host key rotation, ServerAliveInterval, the tilde escapes, ProxyJump, -L tunnels, and PerSourcePenalties, one flag per page.
Set in Space Grotesk, Inter and JetBrains Mono (SIL Open Font License).
OpenSSH behaviour checked against the official OpenBSD manual pages (man.openbsd.org) and the ArchWiki OpenSSH and SSH keys pages, fetched and read during this build: ssh(1); ssh-keygen(1); ssh-agent(1); ssh_config(5); sshd_config(5); together with the Mozilla Infosec OpenSSH guidelines where cited. Flags, defaults and behaviours are named as the documentation names them. Teaching conventions (one flag a day) are named as conventions. This book quotes no verbatim passages and is an independent guide not affiliated with or endorsed by the OpenBSD project or the OpenSSH developers.
General information only. Not professional advice; verify against your own OpenSSH version and the current documentation.
Your purchase is for personal use only. You do not have redistribution rights: please do not share, resell, or republish this book or its pages.
© 2026 Steve Hodgkiss. All rights reserved. Personal use only; no redistribution rights.
Edition 1.0 · stevehodgkiss.net
Contents
The model
What ssh even is: a client and a daemon, and the two directions of trust every connection answers before you see a prompt.
- 01ssh and sshd
- 02The fingerprint yes
ssh (SSH client) is a program for logging into a remote machine and for executing commands on it, intended to provide secure encrypted communications between two untrusted hosts over an insecure network. sshd (the daemon) reads configuration data from /etc/ssh/sshd_config and listens for connections; the Port default is 22. Per ssh(1), sshd(8) and sshd_config(5).
ssh and sshd
Let's say someone says "log in over ssh" like it's one thing. It's two programs and you own one of them.
ssh is the client on your laptop. sshd is the daemon on the server, listening on port 22 by default. You run one command, it connects, and everything after rides an encrypted channel. The Reddit threads mix the names constantly; the distinction is load bearing.
You run ssh. The box runs sshd. Everything else is detail.
Run ps and grep for sshd on any Linux box near you this week. If it's there, that machine accepts connections.
When connecting to a server for the first time, a fingerprint of the server's public key is presented to the user (unless StrictHostKeyChecking has been disabled), with a yes/no/[fingerprint] prompt. Per ssh(1), VERIFYING HOST KEYS.
The fingerprint yes
Let's say you typed ssh user@server and got a wall of text ending in a question. That wall is the only security decision you make all day.
The server shows its host key's fingerprint and asks yes, no, or fingerprint. The right habit: get the real fingerprint another way, from the provider's console or the admin, and compare. Typing yes blind trains you to type yes for attackers too.
The fingerprint check is TOFU: trust on first use. Make the first use honest.
Find one host's real fingerprint out of band this week, its provider console or ssh-keygen on the server, before your next first connect.
Keys
Living by keys: the two halves, the one command that makes them, the signature that proves you, the server's copy, the copy command, the passphrase, the agent, and the permissions that bite.
- 01ssh-keygen, no arguments
- 02ssh-copy-id
- 03The agent
If invoked without any arguments, ssh-keygen will generate an Ed25519 key. The type is specified with -t; supported types include ecdsa, ed25519, rsa. RSA's default size is 3072 bits. Per ssh-keygen(1) and the ArchWiki SSH keys page.
ssh-keygen, no arguments
Let's say a tutorial tells you a wall of flags to make a key. You need none of them.
ssh-keygen with no arguments makes an Ed25519 key, the modern default, at ~/.ssh/id_ed25519. It asks for a passphrase, page 12 covers why to give one. Older guides push RSA at 3072 bits; that's the compatibility option, not the first choice.
Bare ssh-keygen. Answer the prompts. Done.
Generate your next key with zero flags this week, just ssh-keygen, and read each prompt it gives you.
The user should copy the public key to ~/.ssh/authorized_keys on the remote machine; ssh-copy-id installs an identity on the remote machine by appending the public key to authorized_keys, using ssh for the transport. Per ssh(1) AUTHENTICATION and the ArchWiki SSH keys page (Copying the public key to the remote server).
ssh-copy-id
Let's say you're about to nano a public key onto a server by hand. There's a command whose whole job is this.
ssh-copy-id user@server sshs in with your password one last time, appends the public line to authorized_keys, fixes nothing else, and from then on keys own the login. Give it -i and a specific .pub file when you keep more than one key.
One append over ssh. That's the whole ceremony.
Run ssh-copy-id to one host you still password into this week. Then log out and back in without the password.
ssh-agent is a program to hold private keys used for public key authentication; through environment variables the agent can be located and automatically used when logging in to other machines. Keys are added using ssh-add or by ssh when AddKeysToAgent is set in ssh_config(5). Per ssh-agent(1).
The agent
Let's say the passphrase tax is why you left it empty. The agent is the honest fix.
ssh-agent holds your decrypted key in memory. Type the passphrase once, ssh-add loads it, and every ssh after asks the agent to sign. AddKeysToAgent yes in your config loads it on first use, automatically. Keys never leave memory, and laptops usually start one for you.
Passphrase for safety, agent for sanity. Take both.
Run ssh-add -l this week. Empty means nothing held; add your key and feel the difference for a day.
ssh obtains configuration from command-line options, the user's file ~/.ssh/config, then /etc/ssh/ssh_config; since the first obtained value is used, host-specific declarations should be near the beginning and general defaults at the end. Host restricts the following declarations to matching hosts, and a single * pattern provides global defaults. Per ssh_config(5).
~/.ssh/config
Let's say you type the same long user@host string ten times a day. The config file exists so you never type it again.
In ~/.ssh/config, a Host line starts a stanza: Hostname, User, Port, IdentityFile, anything. Then ssh web is the whole command. Order is law: first value wins, so specific hosts go up top and Host * defaults at the end.
Every flag you know lives in this file. Your hosts get short names.
Write one stanza for the host you touch most this week. ssh shortname from then on.
Whenever changing the sshd configuration, use sshd in test mode before restarting the service to ensure it will start cleanly; valid configurations produce no output, via sshd -t. Per the ArchWiki OpenSSH page, Server usage section.
sshd -t first, always
Let's say you edited sshd_config and you're about to restart the daemon. One command decides whether you still own the box.
sshd -t parses the config and prints nothing when it's valid. A typo that survives to restart can kill the daemon, and with it your way in. Keep the current session open while you test and restart, always.
Edit, test, restart, in that order, with a door still open.
Get into the habit this week: after any sshd_config edit, sshd -t before the restart, every time.