SSH: Tutorial & Best Practices

The encrypted door into every Linux server — how to walk through it, and how to lock it behind you.

What It Is

SSH — the Secure Shell — is how you get a command line on a computer that isn't in front of you. You type ssh user@server on your laptop, and a heartbeat later you're typing commands on a machine in another country, every keystroke wrapped in encryption nobody can read. Rent a server from any hoster on earth and the welcome email hands you an SSH command, because SSH is simply how you get in. It's the front door, and there's only one.

Here's a secret to make you feel at home before we even start: you almost certainly use SSH already and don't know it. Every time you git push, you're opening an SSH connection — GitHub is just a server with your key on file. So this isn't a new thing to learn; it's the name for something you've been trusting all along. By the end of this page you'll understand exactly what happens in that half-second after you hit Enter, and — more importantly — how to make sure you're the only one who can walk through your door.

One bit of vocabulary so we don't trip later. SSH is a protocol, and the program you actually run is OpenSSH, which ships on virtually every Linux and Mac — and, as of a few years ago, even Windows bundles it out of the box, so the front door is now genuinely everywhere. It has two halves we'll keep carefully apart: the client (the ssh command you type) and the server (a quiet background daemon called sshd that sits on the far machine, listening on port 22, waiting for someone to knock). Most of this page is about that server — because the moment it's online, a lot of someones start knocking.

Your First Login

Let's just walk through the door, because it really is this easy. You have a server's address and an account on it:

ssh alice@server.example.com

The very first time, you get one odd question — we'll explain it properly later, but for now, the honest answer is yes:

The authenticity of host 'server.example.com' can't be established.
ED25519 key fingerprint is SHA256:P+JhyvKY4CKzf/UgG/Lx6d3feZzMiEYAm+JzHvl40wc.
Are you sure you want to continue connecting (yes/no)? yes

…and you're in:

alice@server:~$

That's it. You're now typing on a machine you may never physically see, and the café WiFi, your ISP, and everyone in between sees only encrypted noise. Type exit to leave.

For a huge number of people, that's where SSH stays forever — a black box that just works. We're going to open the box, because the small amount of cryptography underneath isn't trivia. Your understanding of it is literally what keeps your server safe. So let's make it simple.

How It Works: Encryption, Made Simple

You want to talk to your server. You don't want anyone in between reading along. So the conversation has to be scrambled in a way only the two ends can unscramble — and that means both ends need to share a secret key.

Which is where it gets hard, and where a genuinely beautiful idea saves the day. Think about it: to agree on a secret key, you'd have to send it across the same wire that's being watched — and now the eavesdropper has the key too. For centuries this was considered unsolvable. You cannot whisper a secret across a crowded room and expect it to stay secret.

The solution is one of the loveliest inventions in all of computing: asymmetric encryption. Asymmetric just means there are two keys instead of one — a matched pair, born together, with a single magic property:

  • a public key, which you can hand to anyone — print it on a t-shirt — and
  • a private key, which you guard with your life.

The magic: anything locked with the public key can only be opened with the private key, and — this is the part that feels like a cheat — you cannot work backward from the public key to the private one. So you can shout your public key across the open internet, the eavesdropper can write it down, frame it, tattoo it on their arm, and it does them no good whatsoever. Only the holder of the matching private key can open what the public key locks.

Sit with that for a second, because it's the whole game. A secret that can travel safely in public.

Now here's how SSH actually uses it, and getting this straight clears up half the confusion people carry for years. Asymmetric crypto is slow — far too slow to encrypt a whole busy session with. So SSH plays the two-key trick exactly once, at the very start, for a single job: to let both ends secretly agree on one shared key that nobody watching could possibly reconstruct. The moment that's done, SSH throws the asymmetric machinery away and switches to ordinary symmetric encryption — the everyday kind where the same key both locks and unlocks — and that fast shared key does the real work of scrambling every keystroke and every byte for the rest of the session. So the famous public/private drama is just the clever handshake at the door; the long conversation inside the room is symmetric, quick, and guarded by a shared secret that was agreed upon but never actually sent. (That handshake, BTW, has a name — Diffie–Hellman key exchange — and we'll meet the people behind it in the history section, because the story is wilder than you'd think.)

Once you believe a secret can travel in public, everything else on this page — logging in, proving who you are, proving the server is who it says — is just that one trick, applied. The handshake answers the two questions every secure connection must ask: are you who you say you are, and is the server who it says it is. Let's do the first one.

You may have noticed that every example here keeps happening to Alice. There's a long-running in-joke that cryptography contains exactly two people — Alice and Bob — endlessly sending each other nervous secret messages. They were born in 1977, in the famous paper where Rivest, Shamir, and Adleman first described public-key crypto; before that, dry academic papers said "party A" and "party B," until the authors gave them names and accidentally cast the most overworked couple in computer science. The cast has grown since: there's Eve, who eavesdrops on the line, and Mallory, who is malicious and likes to tamper with messages in transit. Tuck Mallory away in your mind — he turns up later in this very page, at the worst possible moment.

Your Key: How You Actually Log In

First, let's untangle the thing that quietly confuses everyone in every other tutorial — the relationship between the password and all these keys. Here it is, once and for all:

By the time SSH asks you to log in, the encrypted tunnel from the last section already exists. So even if you just type a password, that password travels inside the tunnel — symmetric-encrypted, unreadable on the wire. (This is the entire reason SSH replaced telnet, which flung passwords across the internet as plain text for anyone to scoop up.) Typing a password into SSH is not insecure in transit. That surprises people, and it's worth saying plainly.

So why bother with keys at all? Because a password is still a secret you hand over — you whisper it (safely) down the tunnel every single time, and a secret you keep handing over is a secret that can be guessed, phished, or reused on another site. A key is a secret you never say out loud at all, not even down the encrypted tunnel. You prove you hold it without ever sending it. That's the whole difference.

And to kill the lingering confusion: your login key is a different key from the ones that built the tunnel. Those handshake keys were temporary — used once to agree the shared session secret, then thrown away. This one is yours, it's permanent, and it has exactly one job: to prove you're you. (Hold that thought — later you'll meet a third key, the server's own permanent one, which proves it's it. Different keys, different jobs. You're now holding two of the puzzle's three pieces.)

You make your key pair with ssh-keygen:

ssh-keygen -t ed25519 -C "alice@laptop"

That creates two files in your ~/.ssh/. The public half is a single short line — this is what you hand out:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBMiABnjRWxPXCEbg/eBlPEdQbkkPNok6UmrOwgC15d7 alice@laptop

Tiny aside that trips everyone up: that alice@laptop on the end is just a comment — a sticky note to yourself. SSH ignores it completely for authentication. Name it alice@laptop, work-key, or do-not-lose-this; only future-you reading authorized_keys cares.

The private half lives in ~/.ssh/id_ed25519, never leaves your machine, and looks like this — much longer, and you never share it, paste it, or email it, ever:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACATIgAZ40VsT1whG4P3gZTxHUG5JDzaJOlJqzsIAteXewAAAJDybY388m2N
...many more lines...
-----END OPENSSH PRIVATE KEY-----

To log in with this, the server needs your public line, appended to ~/.ssh/authorized_keys in your account there. One command does it:

ssh-copy-id alice@server.example.com

Now reconnect, and you're in with no password typed. Under the hood the server used your public key to pose a riddle only your private key could answer — and your private key answered it without ever leaving your laptop. Nothing guessable crossed the wire. The whole internet could have been watching and learned nothing.

And this is exactly how git push works. When you added your SSH key to GitHub, you pasted your public line into their authorized_keys (they call it "SSH keys" in settings, but it's the same file, doing the same job). GitHub is just a very polished server, and you've been doing professional public-key authentication for years without noticing. SSH isn't new to you. It just finally has a name.

A reasonable question lands right about here: couldn't an attacker just guess my private key? In theory, sure. In practice — an Ed25519 private key is one of roughly 2²⁵⁵ possibilities. That number is close to the count of atoms in the observable universe. A machine guessing a billion keys a second would still be at it, comfortably, long after the sun has burned out and the Earth is a cinder. "In theory" is doing an enormous amount of quiet work in that sentence.

Warning

Your private key is you. Anyone who copies that file can become you on every server that trusts your key — silently. Protect it with a passphrase when ssh-keygen asks (it encrypts the key on disk, so a stolen laptop isn't a stolen key), and let ssh-agent remember the passphrase so you only type it once per session.

RSA or Ed25519? (and a quiet word about prime numbers)

You'll meet two kinds of key, and you can tell them apart at a glance by the first word. An Ed25519 key is the short, modern one you just saw — a single tidy line starting ssh-ed25519:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBMiABnjRWxPXCEbg/eBlPEdQbkkPNok6UmrOwgC15d7 alice@laptop

An RSA key starts ssh-rsa and is, frankly, a monster by comparison — here's a 4096-bit one. Same purpose, vastly more bulk, because RSA needs far more raw material to reach the same strength:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDnn/45NGU62xcq+jUsapDr2b7o7J/mL0WjTYsSiMZH3mRJ5z
Ee3+rBqmaEmGqbzSTtKhSQaEukXydn6rHG...  (and on, and on, for hundreds more characters)

So where does RSA's strength come from? Prime numbers. You take two enormous primes, multiply them into an even more enormous number, and publish the product — because multiplying is easy, but un-multiplying (factoring the product back into its two primes) is, for big enough numbers, effectively impossible even for every computer on Earth working together. Ed25519 leans on a different hard problem (the arithmetic of points on an elliptic curve), but the spirit is identical: a calculation that's trivial one way and hopeless backward.

And here's the wrinkle almost nobody learns, BTW, and it's a good one: the "primes" RSA uses aren't guaranteed to be prime. Rigorously proving a 2048-bit number prime is slow, so ssh-keygen instead runs probabilistic tests (Miller–Rabin) that pronounce a number prime if it survives enough rounds of random interrogation. The leftover chance it's secretly not prime is smaller than the chance a stray cosmic ray flips a bit in your RAM during the calculation — so we shrug, call them prime, and sleep soundly. Your keys rest, very slightly, on almost certainly. (Welcome to applied cryptography, where "basically never" is a perfectly good engineering answer.)

What's a good length? For RSA, 3072-bit is the modern floor, 4096 is comfortable, and old 1024-bit RSA is considered breakable — never use it. Ed25519 has no dial to fiddle at all: it's one fixed curve delivering about 128 bits of security (roughly equal to 3072-bit RSA) in that one short line — which is rather the point. So the recommendation writes itself:

ssh-keygen -t ed25519

Use Ed25519. Smaller, faster, nothing to misconfigure, and you never think about it again.

But wait — what about quantum computers?

Ah, you've been reading the news — and this is the most interesting corner of the whole subject, the one almost no SSH tutorial will follow you into. You've heard quantum computers will "break encryption." That's roughly true, and the why hides a trap worth understanding. Back in 1994 a mathematician named Peter Shor found an algorithm that, on a sufficiently large quantum computer, factors enormous numbers and cracks discrete logarithms fast — and factoring huge numbers and discrete logs are precisely the hard problems that RSA and elliptic curves lean on for their security. So here's the trap, and the answer to the question you're really asking: elliptic curves do not save you from quantum computers. A big enough quantum machine breaks RSA and Ed25519 alike — in fact it cracks elliptic curves with fewer qubits than RSA, so ECC is arguably the more fragile of the two against this particular future. Elliptic curves are better than RSA against today's ordinary computers (smaller, faster, stronger per bit); against quantum, they're in the same boat — and that boat is sinking.

"But the giant quantum computer doesn't exist yet," you say, and you're right — it may be a decade away, maybe more. So why does anyone care today? Four words that should chill you a little: harvest now, decrypt later. Nothing stops an adversary from recording your encrypted traffic today and simply filing it away until the machine that can crack it finally boots up. Anything you send now that must stay secret in 2040 is, in a sense, already at risk. The clock started a while ago.

Which is where, BTW, a beautiful piece of history is unfolding right now. The American standards body NIST ran a multi-year open competition (2016–2024), inviting cryptographers worldwide to design quantum-resistant algorithms and then publicly try to break each other's. The winner that matters here is ML-KEM (FIPS 203, formerly Kyber), which rests on a completely different hard problem — lattice math, "learning with errors" — that Shor's algorithm simply doesn't touch. A whole new foundation, chosen in the open by the world ganging up on the candidates. That's how you're supposed to pick crypto.

And now the part that ties the bow: SSH already did this. Not "will" — did. OpenSSH has performed hybrid post-quantum key exchange by default since version 9.0 in 2022, and as of OpenSSH 10.0 (2025) the default is the ML-KEM scheme NIST just blessed. "Hybrid" means it runs the classical elliptic-curve exchange and the post-quantum one together and blends both secrets — so the connection stays safe even if one of the two is later broken (belt and braces, the recurring theme of this entire page). Run ssh -v yourserver and squint at the kex: line — there's a fair chance the boring ssh command you've typed a thousand times is already defending you against a computer that doesn't fully exist yet. Note the careful scope, though: this protects the key exchange (the session secret, the thing "harvest now, decrypt later" targets). Your authentication keys — your Ed25519 login key, the server's host key — are still classical, but they matter far less to that attack, because they only prove identity in the moment; there's no recorded session to crack open later.

Anyway — (the beard strokes, the coffee cools) — back to Earth: for logging into servers today, Ed25519 is the right answer, and the protocol wrapped around it is already quietly future-proofing the part that needs it most. On with the show.

Going Deeper: The Server Has a Key Too

Now the part the tutorials skip — and the one that turns SSH from "magic I obey" into "machinery I understand."

You just met the key that proves you to the server. But cast your mind back to your very first login, and that strange prompt about a "host key fingerprint." Why was the server asking you to vouch for it?

Because the server has its own key pair, completely separate from yours — and it uses that key to prove itself to you. The symmetry is the whole point, two pairs pulling in opposite directions:

  • Your key (in ~/.ssh/, public half in the server's authorized_keys) proves you → server.
  • The host key (in /etc/ssh/, public half saved in your known_hosts) proves server → you.

The host key is to the server what your key is to you. It was generated automatically when OpenSSH was installed, and a server's entire cryptographic identity is just a couple of files sitting here:

/etc/ssh/ssh_host_ed25519_key       # the server's PRIVATE host key
/etc/ssh/ssh_host_ed25519_key.pub   # the server's PUBLIC host key

So both ends prove themselves, cryptographically, every single connection. Nobody trusts anybody on faith. That habit — trust nothing, verify everything, with math — is the seed of the entire modern "zero trust" security movement. SSH was doing it in 1995.

Trust on First Use — that first-login prompt, explained

Now that first question makes sense. Your client had never seen this server's host key before, so it asked you to bless it once. When you typed yes, it filed the key's fingerprint in ~/.ssh/known_hosts, and from then on it silently checks — every single connection — that the server still presents the same host key. Trust once, then guarantee sameness forever. (And yes: this is the exact prompt GitHub gave you the first time you pushed. Same machinery, all the way down.)

"Host key changed" — the warning that earns its scary face

One day you connect and get a wall of ASCII alarm:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!

The server presented a different host key than the one in your known_hosts, so SSH slammed the door. Two explanations, and knowing which is which is the difference between a junior and a senior:

  • Innocent (99.99% of the time): the server was rebuilt, reinstalled, or reprovisioned by the hoster — or you simply booted it into your hoster's recovery environment, which is a different little operating system with its own host keys. Any of these mints fresh keys. Clear the stale entry — ssh-keygen -R server.example.com — and reconnect.
  • Sinister (the 0.01% this warning exists for): someone has wedged themselves between you and the server — a man-in-the-middle — presenting their key so they can sit in the middle and read everything. This, at last, is Mallory: the eavesdropper who doesn't just listen but actively impersonates the server to get between you and it. This banner is the entire reason he usually fails.

The discipline to build: never reflexively delete the line just to make the warning go away. Pause and ask why the key changed. Nearly every time it's a rebuild and you'll feel a little silly. But the one time in ten thousand it isn't, this annoying banner is the only thing standing between you and a hijacked session — and you'll be very glad you trained yourself to stop.

How I'm Using It

Enough theory — here's the actual routine I run every time a fresh server lands in my lap. It takes five minutes, and it's the same little dance every time.

1. Get my key on first — while the password still works. Belt before braces:

ssh-copy-id alice@new-server
ssh alice@new-server          # prove the key logs me in, no password

2. Open a second window and leave it connected. This is the rule that separates people who've locked themselves out of a remote box from people who haven't. If I fat-finger the config, this still-open session is my lifeline back in.

3. Harden sshd_config. I open /etc/ssh/sshd_config and make sure these lines are present:

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no

…and then — the step everyone forgets — I make sure nothing quietly re-enables what I just turned off. The files in sshd_config.d/ can override the main config, and a hoster's default drop-in cheerfully setting PasswordAuthentication yes will undo your hard work without a peep:

grep -rE "PasswordAuthentication|PermitRootLogin" /etc/ssh/sshd_config /etc/ssh/sshd_config.d/

4. Test the config before applying it. sshd -t checks the syntax and flatly refuses to load a broken file — which is exactly what you want standing between you and a lockout:

sudo sshd -t && sudo systemctl reload sshd

5. Open a third connection to confirm key login still works after the change. Only once that succeeds do I let the safety session from step 2 go.

That's the whole thing. Five minutes, and the box goes from "one of the internet's 200,000-attempts-a-day piñatas" to "nothing a bot can even attempt." Why those exact settings? That's the next two sections — first the threat, so you feel it in your gut, then the full checklist.

The Security Reality: The Whole Internet Is Knocking

Here's the thing new admins refuse to believe until they see it with their own eyes: the instant your server is online, automated bots from every corner of the planet start trying to log in, and they never, ever stop. Not "might." Are. Right now, as you read this.

This is a real, consecutive four-second slice from /var/log/auth.log on an ordinary internet-facing server with no protection turned on (attacker IPs anonymized):

sshd[3801890]: Failed password for invalid user developer from 192.168.123.79 port 47780 ssh2
sshd[3801881]: Connection closed by invalid user azureuser 192.168.123.79 port 47766 [preauth]
sshd[3801998]: Invalid user demo from 192.168.123.79 port 60250
sshd[3801949]: Failed password for invalid user test from 192.168.123.79 port 47796 ssh2
sshd[3801952]: Failed password for root from 192.168.123.79 port 47804 ssh2
sshd[3801983]: Failed password for invalid user vps from 192.168.123.79 port 47808 ssh2
sshd[3802018]: Invalid user zjw from 192.168.123.79 port 60260
sshd[3802020]: Failed password for invalid user craft from 192.168.123.79 port 60266 ssh2
sshd[3802068]: Invalid user minecraft from 192.168.123.79 port 60306

One bot, one IP, dozens of guesses in four seconds — and it's one of thousands. Over the three and a half days this log covered, the server logged 219,790 failed logins: better than one every two seconds, around the clock, forever. A single IP accounted for 124,752 of them — it knocked over a hundred thousand times and never got tired. This is the baseline, idle-Tuesday hum of any server with a public SSH port. You are not special; you are simply on the internet, and the internet sweeps every door.

And the usernames they try are a poem. The most-attempted accounts from that same log:

8058  ubuntu
4790  deploy
4096  test
3327  admin
3180  minecraft
2553  postgres
2247  pi
1877  oracle
1825  ftpuser
1657  hadoop

A grand tour of defaults: cloud images (ubuntu), Raspberry Pis (pi), forgotten database logins (postgres, oracle), and — 3,180 hopeful tries — minecraft, because an astonishing number of hobby game servers sit on the open internet with the password set to, yes, minecraft. The bots aren't clever, and they don't have to be. They have infinite time and billions of doors, and they're betting that somewhere admin/admin still opens one — which, across the whole internet, it does, often enough to keep the knocking worthwhile forever. Notice how relentlessly they try root — the one username they know exists on every Linux box. Leave root password-login on and you've handed them half the puzzle for free.

Now look back at my five-minute routine. Keys-only auth means every one of those 219,790 guesses fails at the door no matter what they type — there's no password to brute-force. We didn't out-fight the bots. We took the fight off the table.

Even the lock has had bugs

SSH's crypto is superb — but "superb" isn't "perfect," and three real stories shape how the pros behave:

  • The Debian weak-key disaster (2008). A well-meaning code change crippled the random-number generator, so for nearly two years every SSH key made on Debian/Ubuntu came from a tiny, predictable set — millions of "secret" keys were quietly guessable. The lesson that stuck: a key is only as strong as the randomness that birthed it.
  • regreSSHion (CVE-2024-6387, 2024). A flaw in sshd itself allowed, in the right conditions, remote code execution as root with no password at all. The doorman, not the door, had the bug. Translation: patching sshd is a security control, not chore.
  • The xz-utils backdoor (CVE-2024-3094, 2024). This one reads like a spy thriller. An attacker spent years as a friendly, tireless open-source volunteer, slowly earning maintainer trust over a compression library that sshd quietly loads — then slipped in a hidden backdoor meant to unlock SSH servers worldwide. It was caught days before shipping to every Linux distro, almost by accident, by one engineer who noticed his SSH logins were running half a second slow. Genuinely one of the best stories in computing — search "the xz backdoor" and read a proper write-up some evening; it'll change how you think about trust. The takeaway for us: the danger isn't always at your front door. Sometimes it's baked into something you trusted upstream.

How to Do It Right

Every tutorial teaches you how to log in. Almost none teach you how to run a server safely — and that's the half that actually matters, because a soft SSH server is the single most common way Linux boxes get owned. So: you now know how it works. Here's how the pros lock it down. Copy them.

The defenses, strongest first. The top three are non-negotiable for anything facing the internet; together they make your box not worth a bot's attention.

  1. Best of all — don't expose SSH to the internet at all. The safest door is the one attackers can't find. If SSH doesn't need to face the world (it usually doesn't), tuck it behind a VPN like WireGuard: port 22 listens only on the private VPN interface, and from the public internet it simply isn't there. All 219,790 daily knocks drop to zero, because there's no door to knock on. This is the gold standard, and it's less work than it sounds.

  2. Keys only — switch passwords off. PasswordAuthentication no. The entire password-guessing swarm now fails at the threshold regardless of what it guesses; you've removed the thing they were attacking. (Test your key first — see the routine above.)

  3. No root logins. PermitRootLogin no, then log in as a normal user and use sudo — which also gives you a record of who did what. The bots' favorite target evaporates.

  4. fail2ban — auto-ban the repeat offenders. It tails your auth log and firewall-blocks any IP that piles up failures. With keys-only auth they already can't get in — but this stops them filling your logs with a quarter-million lines and burning CPU saying "no." Belt and braces.

  5. Firewall allow-list. Connect from a stable address? Use the kernel firewall (nftables) to let port 22 through only from IPs you name, and drop the rest before they can even say hello. Stricter than fail2ban, which only reacts after the knock.

  6. Jump host / bastion. Got a fleet? Expose one hardened gateway and reach everything else only through it — ssh -J bastion web01 hops through in a single command. One well-watched door instead of fifty.

  7. The small knobs. Changing the port (Port 2222) is not real security — a scanner finds it in seconds — but it does quiet the log noise, since most bots only try 22. Also handy: MaxAuthTries 3, AllowUsers alice bob, and two-factor (TOTP) on the boxes that really matter.

Do the top three and you're genuinely done: the knocking continues forever and the door simply never opens. Sorry, Mallory — no luck on this one.

Then keep watching

Hardening isn't a one-time ritual; it's a habit. The move the pros make that the tutorials never mention is simply checking who's been at the door:

  • Who's logged in, and who has been: who for right now, last for the history, and journalctl -u ssh | grep Accepted for every successful login ever. An Accepted line you can't explain is the one alarm you cannot afford to sleep through.
  • Watch the swarm bounce off, live: journalctl -u ssh -f. And honestly? When you're bored some evening, pour a drink and just watch it scroll. It never stops — you can stare for an hour and the failed attempts keep raining down, from Vietnam, from Brazil, from a hacked fridge in Ohio, an endless hypnotic drizzle of other people's bad intentions. It's strangely soothing once you've done the work — but do the hardening below first, so what you're watching is a swarm shattering against a locked door, and not a slow-motion break-in you're enjoying like a movie.
  • Keep sshd patched. regreSSHion and xz both whisper the same thing: update promptly.

Go ahead — restart it. I'll wait.

Last thing, and it's the fear that freezes every beginner mid-edit: "I'm connected over SSH — if I restart the SSH server, won't I cut the branch I'm sitting on?"

No. Go on, do it right now, from inside your session: sudo systemctl restart sshd. … Still there? Of course you are. Your shell didn't even flinch.

Here's the lovely why. When sshd accepts your connection, it forks off a private child process just for you, and that child is what your terminal is wired to. The sshd you just restarted is only the listener — the receptionist who answers new arrivals. Restarting it sacks and rehires the receptionist, but it never touches the dedicated children already looking after established guests. Existing sessions sail on untouched; only brand-new logins pause for the half-second the receptionist's chair is empty.

That's why my routine keeps a second window open and runs sshd -t first. The restart can never lock you out. A config that rejects your next login absolutely can — and the open session is the rope ladder you keep for exactly that.

Where Everything Lives

A map of the files, so the whole thing stops feeling like sorcery:

  • /etc/ssh/sshd_config — the server config (sshd_config). Every hardening line lives here. After editing: sshd -t, then systemctl reload sshd. (And mind the drop-ins in sshd_config.d/.)
  • /etc/ssh/ssh_host_*_key — the server's host keys, its identity. Lose these and every client on earth gets the "host key changed" banner.
  • ~/.ssh/ — your personal corner, which must be mode 0700. SSH is so paranoid it will flatly ignore your keys if the folder is even readable by others — and honestly, good. Be that paranoid too. (chmod 700 ~/.ssh && chmod 600 ~/.ssh/* fixes the most common "my key isn't working" mystery there is.)
    • id_ed25519 / .pub — your private / public key.
    • authorized_keys — public keys allowed into this account. Add a line to grant access; delete it to revoke. (Which raises a sharp question — keep reading.)
    • known_hosts — host keys you've chosen to trust.
    • config — per-host shortcuts, the best quality-of-life file in all of SSH (see the gems).

And here's the sharp question that authorized_keys should make you ask: if a public key is public, what stops an attacker from just adding their public key to my authorized_keys and walking in? The answer is: nothing — except the file's permissions. Writing to your authorized_keys is granting access; it's the entire security boundary. Which is why an attacker who can write that one file already owns the account, and why SSH guards it so jealously. That realization — that the lock is just a list, and the list is just a file — is the moment you start treating file permissions as the serious security tool they are.

The magic trick hiding in authorized_keys

Now for something almost nobody knows the file can do, and it's genuinely delightful. Each line in authorized_keys can carry restrictions that fence a key to one tiny purpose. Picture handing someone a key to your house that only opens the mailbox and nothing else. Like this:

command="/usr/local/bin/backup.sh",no-pty,no-port-forwarding,from="192.168.123.50" ssh-ed25519 AAAAC3Nza...backup@nas

A connection authenticating with that key can do exactly one thing: run backup.sh. It can't get a shell (no-pty). It can't open tunnels (no-port-forwarding). It only works from one IP (from=). Even if the backup machine is fully compromised and the attacker steals that private key, all they can do with it is… run your backup script. From one address. This is how backup systems, deploy bots, and git get SSH access to a server without ever being handed the keys to the kingdom — a single key, welded to a single job. The first time you set one up and watch it refuse to give you a shell, you'll grin.

More Than a Login: SSH Is a Tunnel

Here's the shift that turns SSH from "remote login" into "Swiss army knife": it's a general-purpose encrypted tunnel, and once you see that, all sorts of tricks fall out of it. Some of these you'll find in any decent tutorial. A few you'll find almost nowhere — and those are the ones worth the price of admission.

The greatest hits (most tutorials cover these)

  • Run one command and come straight back. ssh web01 'df -h' runs df on the server, prints the result, drops you home — no interactive session needed. Tiny, and you'll use it ten times a day.
  • Make a remote service appear on your laptop (port forwarding). ssh -L 5432:localhost:5432 web01, and a database that only listens on the server's own localhost now answers on your machine's port 5432, fully encrypted. Your laptop suddenly has a port that's secretly a tunnel to a box in Frankfurt. (-R does the reverse; -D turns SSH into a personal SOCKS proxy for your browser.)
  • Copy files with scp and sftp — same tunnel, same keys, same safety. scp file web01:/tmp/ just works.
  • Stop typing long commands — ~/.ssh/config. Turn ssh -p 2222 deploy@web01.example.com into plain ssh web01 with a small Host web01 block (user, port, key, even a ProxyJump). Set it up once, thank yourself forever.
  • Run a remote GUI app on your local screen. ssh -X server, launch a graphical program, and its window appears on your desktop while it runs a continent away. Pure first-time wonder.

The ones that feel like secrets (almost nobody mentions these)

  • Teleport a whole directory through the pipe. ssh web01 'tar c /data' | tar xv — the remote machine tarballs /data, streams it through the SSH tunnel, and your local tar unpacks it as it lands. No temp files, nothing staged in between; the data never once touches a file along the route. And the kicker: for a first copy of a big tree of many small files, this is often faster than scp or even rsyncscp pays a slow per-file round-trip, and rsync burns time computing checksums to find differences that, on a first copy, don't exist yet. The tar pipe just opens the hose and lets it run. (Once a copy exists and you're syncing changes, rsync pulls ahead — it ships only the bytes that moved.)
  • Rescue a frozen session with ~. — When the connection wedges (laptop slept, WiFi died) and the terminal won't answer even Ctrl-C, type Enter ~ . — newline, tilde, period — and SSH guillotines the dead session and hands your prompt straight back. ~ is SSH's secret escape character; ~? lists the rest. The first time it saves you from killing a whole terminal, it feels like a cheat code.
  • Make repeat logins instant (multiplexing). Put ControlMaster auto and ControlPersist 10m in your ~/.ssh/config, and your second connection to a host rides over the first's already-open tunnel — no handshake, login is instantaneous. Ansible, which fires off dozens of connections, feels twice as fast.
  • And don't forget the forced-command trick from earlier — that command="…" line in authorized_keys that welds a key to a single job. It belongs in this list too; it's just that we needed it back where the file lived.

Troubleshooting & Gotchas

  • Permission denied (publickey). The server refused your key. Usual suspects: your public key isn't in that account's authorized_keys; your ~/.ssh permissions are too loose (must be 0700, files 0600); or the wrong key got offered. Run ssh -v — it narrates exactly which keys it tries and why each bounced. -v is the friend you call first.
  • "Host key changed." Covered above — don't reflexively nuke the line. Confirm a legit rebuild, then ssh-keygen -R hostname.
  • Locked out after a config edit. This is precisely what the second open session and sshd -t are for. Truly stranded? Most hosters offer a web console or rescue mode to fix the file directly.
  • Your key is just… ignored. Almost always permissions — a home directory or ~/.ssh that others can write to makes SSH silently distrust everything inside. chmod as above.
  • Sessions that hang on a network blip. Kill with ~.; add ServerAliveInterval 60 to your config so SSH notices dead links on its own.

History & Philosophy

SSH was born in 1995 out of a break-in. Finnish researcher Tatu Ylönen, after a password-sniffing attack swept his university network, wrote a replacement for telnet and rlogin — protocols that flung your password across the wire in plain text for anyone to scoop up. SSH encrypted the lot, and it spread like wildfire precisely because the old way was so obviously, embarrassingly broken. The original went commercial, so the OpenBSD crew wrote OpenSSH in 1999 as a free implementation — now standing guard on essentially every server alive. The protocol you use is SSH-2, a clean-sheet redesign; SSH-1 had cracks and is long buried.

BTW — ever wondered why SSH lives on port 22 specifically? Lovely little story. When Ylönen had his protocol ready, he wanted a proper well-known port, so he emailed IANA (the people who hand out port numbers) to ask for one. As it happened, port 22 was free — and it sits right between port 21 (ftp) and port 23 (telnet), the two protocols SSH was built to replace. They gave it to him. SSH literally took its seat at the table between the two things it came to bury. You'll never look at :22 the same way again.

And while we're rummaging in the attic, here's the one that genuinely rearranges your sense of how the world works. Public-key cryptography — that "two keys, one public, one private" magic from earlier — was invented twice. The version everyone credits is Diffie, Hellman, and Merkle in 1976, followed by Alice and Bob's parents at RSA in 1977. But years earlier, in secret, inside Britain's intelligence agency GCHQ, a researcher named James Ellis had dreamed up the same idea (he called it "non-secret encryption"), and by 1973–74 his colleagues Clifford Cocks and Malcolm Williamson had worked out what we now call RSA and Diffie-Hellman — and then filed it all in a classified drawer, unable to tell a soul, for over two decades. It stayed secret until 1997. Two sets of brilliant people, on opposite sides of a wall, discovering the same beautiful truth — and only one set got to publish. The thing protecting your git push was a state secret before it was a paper.

The idea worth carrying with you is that SSH quietly solved two problems at once, and most people only ever notice the first. It encrypts the channel — obvious, necessary. But it also baked mutual authentication into the foundation: not just "is this private," but "are both ends who they claim to be," enforced by those two key pairs pulling in opposite directions. Verify identity with math; trust nothing on faith. That second idea outgrew SSH entirely — it's the blueprint behind most secure systems you'll ever touch. Understand both halves, and you don't just know how to use SSH. You know how trust on the internet actually works.

And really, that's the quiet joy of learning this stuff: pull on any single thread — that prompt, that key, that port number — and it unravels into number theory, cold-war espionage, lattice mathematics, and the looming weirdness of quantum physics, all of it connected, all of it reachable from a command you type without thinking. If any of this lit a spark, follow it; Simon Singh's The Code Book is the rabbit hole most of us fell into first, and it's a wonderful place to fall. Then come back, because there's a server waiting and it isn't going to secure itself.

See Also

  • ssh — the client command, every flag and use
  • ssh-keygen — create and manage your keys
  • ssh-copy-id — install your public key on a server
  • ssh-agent / ssh-add — hold your decrypted key for the session
  • scp / sftp — copy files over the same secure tunnel
  • fail2ban — auto-ban the brute-forcers
  • WireGuard — put SSH behind a VPN, the strongest defense
  • sshd_config — the server configuration reference
  • /var/log/auth.log — where every login and attack is recorded
  • SSH keys — public-key crypto, RSA vs Ed25519 in depth

You can't watch your auth log every second — but something should.

CleverUptime watches SSH on every server: it flags root-login-open and password-auth-on before a bot finds them, tells you in plain language exactly which setting to change, and notices when sshd falls behind on patches. See your own server's health in 30 seconds, no signup.