The SSH lesson got you onto a remote server with a password. Professional use goes further: key pairs so nothing secret ever travels over the wire, an agent so you type a passphrase once a day, a config file that turns ssh -i key -p 2222 alice@203.0.113.10 into ssh web, jump hosts for private networks, and tunnels that make a remote database appear on your laptop. This lesson covers each, plus the server-side settings that shut password logins off for good.
A key pair has a private half that stays on your machine and a public half you copy to servers. During login the server sends a challenge that only the private key can sign; the password never exists. Use the Ed25519 algorithm — small, fast and the current default recommendation — and protect the private key with a passphrase.
ssh-keygen -t ed25519 -C "alice@laptop"
# Enter file: (accept ~/.ssh/id_ed25519)
# Enter passphrase: (choose one)
ls -l ~/.ssh
# -rw------- id_ed25519 private key: never share, never copy to servers
# -rw-r--r-- id_ed25519.pub public key: safe to publishInstall the public key on a server. ssh-copy-id appends it to ~/.ssh/authorized_keys on the remote side with the correct permissions:
ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@203.0.113.10
ssh alice@203.0.113.10 # now logs in without a password promptWithout ssh-copy-id (Windows, or a cloud console), do it manually:
cat ~/.ssh/id_ed25519.pub | ssh alice@203.0.113.10 \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"Permissions matter: SSH refuses keys if ~/.ssh is not 700 or authorized_keys is group-writable.
The agent holds decrypted private keys in memory and answers signing requests, so a passphrase-protected key costs one prompt per session.
eval "$(ssh-agent -s)" # start an agent (desktop sessions usually have one)
ssh-add ~/.ssh/id_ed25519 # prompts for the passphrase once
ssh-add -l # list loaded keys
ssh-add -D # remove all~/.ssh/config assigns names to hosts and sets per-host options. Everything you can pass on the command line has a keyword here.
# ~/.ssh/config (chmod 600)
Host web
HostName 203.0.113.10
User alice
Port 2222
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host db
HostName 10.0.0.5
User alice
ProxyJump web
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yesssh web # instead of ssh -p 2222 -i ~/.ssh/id_ed25519 alice@203.0.113.10
scp deploy.tar.gz web:/tmp/
rsync -av ./site/ web:/var/www/site/ServerAliveInterval keeps idle connections open through NAT routers. IdentitiesOnly yes stops SSH from offering every key in the agent, which avoids "too many authentication failures". Patterns like *.example.com apply defaults; the first matching block wins for each option, so put specific hosts before wildcards.
Private servers often have no public IP; you reach them through a bastion. ProxyJump (or -J on the command line) tunnels the connection through it transparently.
ssh -J alice@bastion.example.com alice@10.0.0.5
ssh db # with ProxyJump in the config
scp report.csv db:/srv/data/ # works through the jump tooSSH can carry any TCP connection inside the encrypted session.
| Form | Effect |
|---|---|
| -L local:remotehost:remoteport | local port forwards to a host reachable from the server |
| -R remote:localhost:localport | remote port on the server forwards back to your machine |
| -D 1080 | SOCKS proxy through the server |
| -N | no remote command, tunnel only |
| -f | go to background after connecting |
# Reach a database that only listens on the server's localhost
ssh -L 5433:localhost:5432 -N web
psql -h localhost -p 5433 -U app
# Open an internal admin panel in your browser at http://localhost:8080
ssh -L 8080:10.0.0.20:80 -N web
# Expose your local dev server to a colleague through the server
ssh -R 9000:localhost:3000 -N webOnce keys work, turn passwords off. Edit /etc/ssh/sshd_config (or a drop-in in /etc/ssh/sshd_config.d/):
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
KbdInteractiveAuthentication no
MaxAuthTries 3
AllowUsers alice deploysudo sshd -t # syntax check
sudo systemctl reload ssh # "sshd" on RHEL-familyKeep your current session open while testing a new one from another terminal; if you lock yourself out, the open session lets you undo the change.
ProxyJump.~/.ssh or authorized_keys, which SSH silently ignores; run ssh -v to see why a key was rejected.sshd_config, forgetting sshd -t, and reloading a broken config.PasswordAuthentication yes on an internet-facing server; brute-force attempts start within minutes.-N and getting a shell when you only wanted a tunnel.Which file on the server must contain your public key for key-based login?
ed25519 keys with a passphrase; install the public half with ssh-copy-id; keep ~/.ssh at 700 and keys at 600.ssh-agent and AddKeysToAgent yes mean one passphrase prompt per session.~/.ssh/config gives hosts short names and per-host options; specific blocks go before wildcards.ProxyJump reaches private hosts; -L, -R and -D tunnel ports and proxy traffic.sshd_config, test with sshd -t, and keep a session open while changing it.Next lesson: rsync, File Transfer and Backups — synchronise directories efficiently and build a backup routine you can restore from.