Module 17 · Server-side SSH 55 min

SSH is how Linux people drive a computer that's somewhere else — across the room, across the city, across the world. Same idea as Windows Remote Desktop, but faster and works anywhere. Every real Linux server is run through SSH. By the end of this module you'll log in with a key (no password), keep your settings tidy, lock the server down, copy files in and out, and even reach services hidden behind a firewall.

By the end of this module, you will:

  • Generate an SSH key pair and deploy it to a remote server
  • Use the SSH config file to manage multiple servers
  • Harden an SSH server by editing sshd_config
  • Transfer files with scp and rsync
  • Create an SSH tunnel to forward a remote port locally
  • Use ssh-agent to avoid retyping your passphrase every connection
  • Verify host fingerprints and understand the known_hosts file

Why Linux folks pick SSH over Remote Desktop

Windows Remote Desktop sends you the whole picture of the other computer — every pixel, every animation. That eats a lot of internet. SSH only sends text: you type a command, the answer comes back. That's it. A full SSH session uses about as much internet as sending a text message. You can run a server on the other side of the world from a wobbly hotel Wi-Fi and it still feels snappy. Remote Desktop is for desktops; SSH is for servers.

How key login actually works

Instead of a password, you make two matching keys at the same time. One is the private key — it stays on your laptop and you never give it to anyone. The other is the public key — you put a copy on every server you want to log into. When you connect, the server sends a little puzzle that only your private key can solve. You solve it, the server lets you in, and your password never travels over the internet. Even if someone breaks into the server, they only get the public key — which is useless on its own.

Logging in with a key instead of a password

Generating and deploying SSH keys
# ── Step 1: Generate a key pair on your LOCAL machine ─────
user@laptop:~$ ssh-keygen -t ed25519 -C "alice@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519): [Enter]
Enter passphrase (empty for no passphrase): [strong passphrase]
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub

# ── Step 2: Copy your public key to the server ────────────
user@laptop:~$ ssh-copy-id alice@192.168.1.100
Number of key(s) added: 1
Now try logging into the machine: ssh alice@192.168.1.100

# ── What ssh-copy-id does (if you need to do it manually) ─
user@laptop:~$ cat ~/.ssh/id_ed25519.pub # view your public key
# On the server, append it to: ~/.ssh/authorized_keys
# chmod 600 ~/.ssh/authorized_keys (required — SSH refuses to work if too open)
# chmod 700 ~/.ssh/ (directory permissions matter too)

# ── Step 3: Connect with your key ─────────────────────────
user@laptop:~$ ssh alice@192.168.1.100
Welcome to Ubuntu 24.04 LTS
alice@server:~$

Pick ed25519 when you make a key

There are a few flavours of SSH key. The modern one is called ed25519. It's shorter, faster, and safer than the older RSA kind. The public key fits on one line; an RSA one is a fat blob. Always put -t ed25519 on the command when you make a new key. The only time you fall back to -t rsa -b 4096 is on a really old server that doesn't speak ed25519 yet.

The SSH config file — give every server a nickname

Typing ssh -i ~/.ssh/id_ed25519 -p 2222 alice@192.168.1.100 every time is painful. Instead, write each server's details once in a little file called ~/.ssh/config and pick a nickname for it. After that, ssh myserver is all you need to type. It's one of SSH's best features and almost nobody knows about it.

~/.ssh/config — managing multiple servers
# One entry per server. Indented fields belong to the Host above.

Host myserver
HostName 192.168.1.100
User alice
Port 22
IdentityFile ~/.ssh/id_ed25519

Host prod-web
HostName 203.0.113.42
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519_prod

Host bastion
HostName jump.example.com
User ec2-user
IdentityFile ~/.ssh/id_ed25519

# Global defaults apply to all hosts not matched above
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes

# Now connect with just the shortcut name:
user@laptop:~$ ssh myserver # uses all the settings above
user@laptop:~$ ssh prod-web # connects to the production server
user@laptop:~$ scp myserver:/etc/nginx/nginx.conf . # scp also uses the config

Locking down the SSH server

Out of the box, SSH works — but it's not locked down. The second a new server goes on the internet, robots start guessing passwords at it. Within minutes. So you turn off password login, block anyone trying to log in as the admin (root) directly, and optionally move SSH to a different port number to make the log files easier to read.

/etc/ssh/sshd_config — hardening settings
# Edit with: sudo nano /etc/ssh/sshd_config

# ── Disable direct root login ─────────────────────────────
PermitRootLogin no
# Root can still be reached via: ssh user@server, then sudo su

# ── Disable password authentication (keys only) ──────────
PasswordAuthentication no
# IMPORTANT: have your key deployed BEFORE setting this!
# If you lock yourself out, you'll need console access to fix it.

# ── Change the default port (reduces log noise) ──────────
Port 2222
# Bots scan port 22. Moving doesn't stop determined attackers
# but reduces automated brute-force attempts by ~95%

# ── Other useful hardening options ───────────────────────
MaxAuthTries 3
LoginGraceTime 20
AllowUsers alice bob
# Only the listed users can SSH in. Everyone else is blocked.

# ── Apply changes ─────────────────────────────────────────
root@server:~$ sudo sshd -t # test config for errors FIRST
root@server:~$ sudo systemctl reload sshd # reload without dropping connections

# ── Open the new port in UFW ──────────────────────────────
root@server:~$ sudo ufw allow 2222/tcp
root@server:~$ sudo ufw delete allow ssh # remove the old port 22 rule

Always keep a backup window open

Before you reload SSH with new settings, open a second SSH window to the same server and leave it open. If you made a typo in the config and SSH stops accepting new logins, that second window is still live — you can fix the file and try again. If you close your only window during a change and the new config is broken, you're locked out until you can get to the server in person.

Copying files in and out — scp and rsync

scp and rsync — moving files over SSH
# ── scp — secure copy (simple, good for single files) ─────
user@laptop:~$ scp report.pdf alice@myserver:/home/alice/
user@laptop:~$ scp alice@myserver:/etc/nginx/nginx.conf . # download
user@laptop:~$ scp -r mydir/ alice@myserver:/tmp/ # copy directory

# ── rsync — smarter, faster, resumable ───────────────────
user@laptop:~$ rsync -avz local/ alice@myserver:/remote/
# -a = archive (preserve permissions, timestamps, symlinks)
# -v = verbose
# -z = compress in transit

# Only transfers CHANGED files — skips unchanged ones
# If interrupted, re-run the same command — it resumes

user@laptop:~$ rsync -avz --delete local/ alice@myserver:/remote/
# --delete removes files on remote that no longer exist locally
# Use with caution — it makes remote an EXACT mirror

user@laptop:~$ rsync -avzn local/ alice@myserver:/remote/
# -n (or --dry-run) shows what WOULD be transferred without doing it
# Always do a dry run before using --delete for the first time
What you care aboutscprsync
Second time you run itCopies every file all over againOnly copies the files that changed
If the connection dies halfwayYou have to start from scratchJust run it again — it picks up where it stopped
Keeping permissions and datesOnly with -pYou get it for free with -a
What it's good forA single file, a quick one-offFolders, backups, syncing whole projects
The Windows tool that does the sameWinSCP, for one fileRobocopy /MIR

SSH tunnels — reaching things hidden behind a firewall

SSH can do a clever trick: it can carry other internet traffic through itself, all wrapped up safely inside the SSH connection. That means you can use a service running on the far server (a database, a web admin page, anything) as if it were running on your own laptop — even if the company firewall only lets SSH through and blocks everything else.

SSH tunnels — local forwarding and jump hosts
# ── Local port forwarding ─────────────────────────────────
# Access a remote web server at localhost:8080
user@laptop:~$ ssh -L 8080:localhost:80 alice@myserver
# Now open http://localhost:8080 — traffic tunnels to myserver:80
# Useful for: accessing admin panels, databases, web UIs behind firewalls

# ── More specific examples ────────────────────────────────
user@laptop:~$ ssh -L 5433:db-server:5432 alice@myserver
# Access remote PostgreSQL (db-server:5432) at localhost:5433
# Connect your local psql/DBeaver to localhost:5433

user@laptop:~$ ssh -L 8080:localhost:80 -N -f alice@myserver
# -N = don't execute a command (tunnel only) -f = run in background

# ── Jump hosts (bastion servers) ─────────────────────────
# Access internal-server that is only reachable via a bastion
user@laptop:~$ ssh -J bastion.example.com alice@internal-server
# -J = jump through this host first
# In ~/.ssh/config: ProxyJump bastion (under Host internal-server)

Connecting to Linux from a Windows machine

Most people who learn SSH are still on Windows when they start. Good news: you don't need to install Linux first. Here are the tools you'll actually use.

Windows Terminal — SSH is already there

Windows 10 (and Windows 11) have SSH built right in — you don't have to install anything. Open Windows Terminal or PowerShell and type ssh user@server-ip. It works exactly like SSH on Linux: the same ssh-keygen to make a key, the same ~/.ssh/config file for nicknames, the same ssh-copy-id to send your key to a server. Your keys end up in C:\Users\YourName\.ssh\. This is the way to go on any modern Windows.

PuTTY — for older Windows and many company laptops

PuTTY is a free SSH program (putty.org). It's been around forever and lots of French company laptops still use it. PuTTY uses its own key file ending in .ppk instead of the normal SSH format. You make one with PuTTYgen, which comes with PuTTY. The steps are: (1) Make a PPK key in PuTTYgen. (2) Copy the public-key text from PuTTYgen into ~/.ssh/authorized_keys on the server. (3) In PuTTY, go to Connection → SSH → Auth and point it at your .ppk file. Save the session and from then on it's a double-click to log in.

Moving files between Windows and Linux

WinSCP (winscp.net) is the friendly way: it shows you Windows on one side and the Linux server on the other, and you drag files between the two windows — same as Windows Explorer. PSCP is the command-line tool that ships with PuTTY. From PowerShell you'd type something like pscp C:\file.txt user@server:/home/user/. If you're already using Windows Terminal with the built-in SSH, the normal scp command works exactly like it does on Linux.

The five things to remember

  • A key pair is safer than a password. The private half stays on your laptop forever; the public half goes on every server, in ~/.ssh/authorized_keys.
  • The ~/.ssh/config file lets you make nicknames for servers — ssh myserver instead of a giant 60-character command.
  • On any real server, switch off password login (PasswordAuthentication no) and direct admin login (PermitRootLogin no) — but only after your key works.
  • For copying folders, use rsync instead of scp. It's faster, it picks up where it left off, and with --delete it can mirror a folder exactly.
  • SSH tunnels let you reach a database, a web admin page, or anything else on the far server as if it were running on your own laptop — all through one SSH connection.

The truth about moving SSH off port 22

Lots of guides (including this one) tell you to move SSH from the standard port 22 to a different number. Doing this makes your log files quieter, because the automatic robots that scan port 22 stop finding you. But it does not actually make you safer. A real attacker scans every port on your server and finds SSH in a few seconds, wherever you put it. The things that genuinely keep you safe are: using a key instead of a password (which you already do), turning off password login (PasswordAuthentication no), and a tool called fail2ban that bans IP addresses that try too many bad logins. Change the port if you like a tidier log — but don't believe it's security.

ProxyJump — only when you need it

Some servers can't be reached straight from the internet — you have to log into another server first (called a "jump host" or "bastion") and then hop from there to the one you want. ProxyJump in ~/.ssh/config sets that up so it feels like one step. It's an advanced feature. If your job today doesn't involve hopping through bastion servers, skip this and come back when you need it. The everyday SSH skills — keys, ssh-copy-id, the config file — are what matters first.

The SSH agent — type your passphrase once, not every time

You should put a passphrase on your private key (it's basically a password for the key itself — it means a thief who steals your laptop can't also walk into your servers). But typing that passphrase every single time you SSH would be horrible. That's what the SSH agent is for. The agent holds your unlocked key in memory while you're logged in to your laptop, hands it over to ssh when needed, and forgets it the moment you log out.

ssh-agent + ssh-add
# Most modern desktops auto-start the agent. Confirm yours is running:
user@ubuntu:~$ ssh-add -l
The agent has no identities.

# Add your default key (you'll be prompted for the passphrase ONCE)
user@ubuntu:~$ ssh-add
Enter passphrase for /home/you/.ssh/id_ed25519:
Identity added: /home/you/.ssh/id_ed25519

# From now on, ssh, scp, rsync, git over SSH all "just work" — no prompts.
user@ubuntu:~$ ssh production # silent — agent provided the key

# Add a non-default key (any other private key file)
user@ubuntu:~$ ssh-add ~/.ssh/work_key

# Forget all loaded keys (good before walking away from your machine)
user@ubuntu:~$ ssh-add -D

Agent forwarding (ssh -A server, or ForwardAgent yes in your config file) is a related trick: once you're SSH'd into one server, that server can use your laptop's agent to log in to a third server — handy when you want to run a git pull on the remote machine without leaving a copy of your private key there. Use it sparingly. Anyone who's admin on the middle server can quietly use your agent while you're connected. Only turn it on for machines you actually trust.

Known hosts — making sure you're talking to the right server

The first time you SSH to a new server, it shows you a strange prompt:

first SSH connection
The authenticity of host '203.0.113.42 (203.0.113.42)' can't be established.
ED25519 key fingerprint is SHA256:abc123…XYZ
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Almost everyone types "yes" without reading it. Don't. That long string is the server's fingerprint — its unique ID. If you say yes to the wrong fingerprint, you might be trusting a sneaky attacker pretending to be your server (this is called a man-in-the-middle attack). The right move: get the real fingerprint from your hosting provider's control panel, or from a colleague who already manages this server, and only type "yes" if the two match.

What you want to do Command
Find a server's own fingerprint (run this on the server)ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
List every server your laptop has trusted beforessh-keygen -l -f ~/.ssh/known_hosts
Forget a server (e.g. it was reinstalled)ssh-keygen -R hostname
You see "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!"Either someone really did rebuild the server — or somebody is trying to trick you. Ask the server owner before you run ssh-keygen -R and reconnect.

Good habit: when you set up a new server, copy its ssh_host_ed25519_key.pub fingerprint into your password manager next to its IP address. Then the first time you SSH in, you compare what you see to what you saved — no guessing.