SSH Keys, Config File and Tunnels

Advanced
13 min

SSH Keys, Config File and Tunnels

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.

How Key Authentication Works

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.

bash
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 publish

Install the public key on a server. ssh-copy-id appends it to ~/.ssh/authorized_keys on the remote side with the correct permissions:

bash
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 prompt

Without ssh-copy-id (Windows, or a cloud console), do it manually:

bash
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.

ssh-agent: Type the Passphrase Once

The agent holds decrypted private keys in memory and answers signing requests, so a passphrase-protected key costs one prompt per session.

bash
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

The Client Config File

~/.ssh/config assigns names to hosts and sets per-host options. Everything you can pass on the command line has a keyword here.

bash
# ~/.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 yes
bash
ssh 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.

Jump Hosts

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.

bash
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 too

Port Forwarding and Tunnels

SSH 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 |

bash
# 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 web

Hardening the Server

Once keys work, turn passwords off. Edit /etc/ssh/sshd_config (or a drop-in in /etc/ssh/sshd_config.d/):

bash
PasswordAuthentication no PubkeyAuthentication yes PermitRootLogin no KbdInteractiveAuthentication no MaxAuthTries 3 AllowUsers alice deploy
bash
sudo sshd -t # syntax check sudo systemctl reload ssh # "sshd" on RHEL-family

Keep 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.

Common Mistakes

  • Copying the private key to the server "so it can log in elsewhere". Generate a separate key there or use agent forwarding or ProxyJump.
  • Wrong permissions on ~/.ssh or authorized_keys, which SSH silently ignores; run ssh -v to see why a key was rejected.
  • Editing sshd_config, forgetting sshd -t, and reloading a broken config.
  • Leaving PasswordAuthentication yes on an internet-facing server; brute-force attempts start within minutes.
  • Forgetting -N and getting a shell when you only wanted a tunnel.
Quick Quiz
Question 1 of 3

Which file on the server must contain your public key for key-based login?

Key Takeaways

  • Generate 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.
  • Disable password and root logins in 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.

SSH Keys, Config File and Tunnels - Linux & Command Line | CodeYourCraft | CodeYourCraft