Lesson 11 of 19 · Level 2 — Intermediate: troubleshooting
SSH, keys & remote work
Work on remote servers safely and efficiently: key-based login, the SSH agent, a tidy ~/.ssh/config, jump hosts, copying files with scp and rsync, and tmux so long jobs survive a dropped connection.
Why keys instead of passwords
Passwords can be guessed, reused and phished. SSH keys are a pair: a private key that never leaves your laptop, and a public key you place on servers. The server checks you hold the private key without it ever being sent.
A public key is like a padlock you hand out to every server: anyone can have one. Your private key is the only key that opens those padlocks, and it stays in your pocket. When you arrive, the server snaps your padlock shut on a little box and asks you to open it. Only the real you can.
Create and install a key
$ ssh-keygen -t ed25519 -C "asha@laptop"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/asha/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
$ ssh-copy-id asha@web-01
Number of key(s) added: 1
$ ssh asha@web-01
ssh-copy-id appends your public key (id_ed25519.pub) to the server's ~/.ssh/authorized_keys with the right permissions. Use a passphrase, and let the agent remember it:
$ eval "$(ssh-agent -s)" # usually already running on desktops
$ ssh-add ~/.ssh/id_ed25519
Permissions matter to sshd
On the server: home directory not writable by others, ~/.ssh 700, authorized_keys 600, all owned by the user. Otherwise sshd silently ignores the keys. ssh -v on the client, and journalctl -u ssh (or /var/log/auth.log) on the server, tell you why.
A tidy ~/.ssh/config
Stop typing long commands:
Host bastion
HostName bastion.example.com
User asha
Host web-*
User asha
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Host web-01
HostName 10.0.5.20
Now ssh web-01 jumps through the bastion automatically, and scp, rsync and Ansible pick up the same settings.
Moving files
$ scp app.tar.gz web-01:/tmp/ # one file
$ rsync -avz --progress ./site/ web-01:/srv/site/ # a directory; only changes are sent
$ rsync -avz --delete ./site/ web-01:/srv/site/ # also delete remote files removed locally (careful)
With rsync, the trailing slash matters: ./site/ copies the contents of site; ./site copies the directory itself.
Tunnels: reach what isn't exposed
$ ssh -L 5432:localhost:5432 db-01 # laptop:5432 → db-01's own localhost:5432
$ psql -h localhost -p 5432 -U app # in another terminal, as if the DB were local
Handy for admin UIs and databases that (correctly) only listen on localhost.
tmux: sessions that survive disconnects
$ tmux new -s upgrade
# ... start a long job, e.g. an OS upgrade ...
# press Ctrl+b then d to detach; close your laptop
$ ssh web-01
$ tmux attach -t upgrade # still running, output intact
Try it: set up a clean SSH workflow
With two VMs (or a VM and your laptop):
- Create an ed25519 key with a passphrase, install it with
ssh-copy-id, and log in without a password. - Break it on purpose:
chmod 777 ~/.sshon the server, try again withssh -v, and find the reason in the server's auth log. Fix it (chmod 700 ~/.ssh). - Write a
~/.ssh/configentry sossh labworks. - Start
tmux new -s test, runtop, detach, log out, log back in and re-attach. rsynca folder to the server twice, and notice how fast the second run is.
Going deeper: SSH at scale
- Harden sshd (
/etc/ssh/sshd_config, validate withsudo sshd -t):PasswordAuthentication no,PermitRootLogin no, allow only specific groups (AllowGroups). Keep a second session open while changing it, so a mistake can't lock you out. - SSH certificates (signed by an SSH CA, short-lived) scale far better than copying public keys to hundreds of servers, and make revocation real.
- Prefer hardware-backed keys (
ed25519-skwith a FIDO2 security key) for privileged access. - For fleets, reduce interactive SSH altogether: configuration management, immutable images and centralised logs mean you log in only to investigate. See Linux Level 3: host hardening.
Recap
- Use ed25519 keys with a passphrase and the agent; only the public key goes on servers.
~/.ssh700,authorized_keys600, or sshd ignores them;ssh -vand the auth log explain failures.~/.ssh/config+ ProxyJump for bastions; rsync for directories; -L tunnels for private services.- Run long jobs in tmux so a dropped connection doesn't kill them.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.