Linux — Level by Level›11 · SSH, keys & remote work

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.

Practitioner
Key wordssshkey paired25519authorized_keysssh-agent~/.ssh/configProxyJumpscprsynctmux

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):

  1. Create an ed25519 key with a passphrase, install it with ssh-copy-id, and log in without a password.
  2. Break it on purpose: chmod 777 ~/.ssh on the server, try again with ssh -v, and find the reason in the server's auth log. Fix it (chmod 700 ~/.ssh).
  3. Write a ~/.ssh/config entry so ssh lab works.
  4. Start tmux new -s test, run top, detach, log out, log back in and re-attach.
  5. rsync a 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 with sudo 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-sk with 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.
  • ~/.ssh 700, authorized_keys 600, or sshd ignores them; ssh -v and 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.