What Is SSH? A Clear Explanation (2026)

What Is SSH? A Clear Explanation (2026)

SSH is a network protocol that lets you log into a remote computer over an untrusted network and run commands there securely. The abbreviation stands for Secure Shell. Everything travelling between your machine and the server — keystrokes, output, transferred files, passwords — is encrypted and protected against tampering.

That is the short answer. The longer one is more interesting, because most explanations stop at the same place: they show you how to generate a key and then call keys a “more convenient” alternative to passwords. That phrasing is not just imprecise, it is dangerous — because it presents a security decision as a comfort preference.

This article explains SSH from the ground up and backs the important claims with numbers from our own operations. For this piece we analysed the journal of our main server: 26,753 failed login attempts from 2,874 distinct IP addresses over 22 days — and found something in it that turns the chapter “keys vs. passwords” from an opinion into a measurement.

A glowing encrypted tunnel stretching between two server towers through a dark space

What is SSH? The problem it solved

To understand what SSH is, it helps to look at what it replaced. Before SSH, people logged into remote machines using Telnet, rlogin or rsh. Those protocols worked — they just transmitted everything in plain text. The password you typed travelled across the network as readable text. Anyone who could listen in anywhere along the path had it.

In 1995, Tatu Ylönen built the first version of SSH at Helsinki University of Technology after his network became the target of a password-sniffing attack. The protocol was later reworked and exists today as SSH-2, standardised in RFCs 4251 through 4254 in 2006. The vast majority of installations run OpenSSH, a free implementation from the OpenBSD project.

On our server that looks like this:

OpenSSH_9.6p1 Ubuntu-3ubuntu13.19, OpenSSL 3.0.13

SSH solves three problems at once, and that three-way split is the key to understanding it:

  1. Confidentiality — nobody along the path can read along, because the connection is encrypted.
  2. Integrity — nobody along the path can change anything unnoticed, because every packet carries a cryptographic checksum.
  3. Authenticity — and in both directions: the server verifies that you are who you claim to be. And your client verifies that the server is the one you spoke to last time.

The third point is almost always glossed over when learning, because it disguises itself as an annoying warning message. It is the one that prevents an attack that encryption alone would be powerless against. More on that below.

How an SSH connection is actually established

When you type ssh user@server, four things happen in sequence within a few hundred milliseconds. The order matters, because it explains why certain error messages appear before you ever got the chance to type a password.

Step 1: Version exchange. Both sides state which protocol version they speak. This is the only part that runs in plain text.

Step 2: Key exchange (KEX). Client and server agree on a method and derive a shared secret session key from it — without ever sending that key across the wire. This is the actual magic of modern cryptography. From here on, everything is encrypted.

Step 3: Server authentication. The server proves with its host key that it is who it claims to be. Your client compares this against what is stored in ~/.ssh/known_hosts.

Step 4: Client authentication. Only now do you identify yourself — by key or by password.

You can inspect what gets negotiated yourself. ssh -v shows the negotiation. On our server:

debug1: kex: algorithm: sntrup761x25519-sha512@openssh.com
debug1: kex: host key algorithm: ssh-ed25519
debug1: kex: server->client cipher: chacha20-poly1305@openssh.com
debug1: Server host key: ssh-ed25519 SHA256:KtZdIhCO3vbjDpSfd/oermLTrfODaOGjVUc1VyEg0EM

The first line deserves a moment of attention. sntrup761x25519 is a hybrid, post-quantum-safe method: it combines classical X25519 with Streamlined NTRU Prime. The background is an attack class called harvest now, decrypt later — someone records encrypted traffic today and decrypts it once capable quantum computers exist. OpenSSH made this method the default in version 9.0. Which means anyone running a current OpenSSH already has this protection — without having configured anything.

We measured how long all of that takes. Five connection setups with an immediate exit afterwards:

RunDuration
10.21 s
20.18 s
30.19 s
40.19 s
50.17 s

Roughly 190 milliseconds for connection setup, key exchange, mutual authentication and teardown. That is the price of every new SSH session — and the reason it pays off to reuse connections when a script does something on the same server a hundred times in a row. There is a concrete setting for that further down.

Keys and passwords: not a comfort question, but two different security models

This is the section that actually matters.

An SSH key pair consists of two matching files. The private key stays on your machine and never leaves it. The public key is copied to the server, into the file ~/.ssh/authorized_keys. When you log in, the server sends you a random challenge that only the private key can solve. You send back the solution — not the key.

Two interlocking swirls of light, one gold and one silver, as an image of the matching key pair

That is precisely the crucial difference: with password authentication you transmit the secret itself. It is encrypted in transit, yes, but the server gets to see it. With key authentication you transmit only a proof that you possess the secret. The private key never leaves your disk — not even in encrypted form, not even briefly.

Three consequences follow from this, none of which have anything to do with convenience:

  • A compromised or spoofed server can harvest your password. It cannot harvest your private key.
  • A password a human can memorise is guessable. An Ed25519 key is not.
  • The same password is often reused across systems. A key is typically generated per device and can be revoked individually.

The evidence from our own journal

And now the measurement that turns this section from an opinion into a finding. We analysed the SSH journal of our main server across the entire available window — from 24 August to 15 September 2026, so 22 days:

MetricValue
Failed login attempts26,753
Distinct attacking IP addresses2,874
Successful logins85
Of those, by key (publickey)85
Of those, by password0
Log entries reading “Failed password”0

The last row is the interesting one, and it briefly made me suspicious while measuring. Zero failed password attempts across 26,753 attacks — at first that looked like a fault in the measuring instrument. It is not. The explanation is in the configuration:

passwordauthentication no
kbdinteractiveauthentication no
permitrootlogin without-password
pubkeyauthentication yes

Because password authentication is switched off, a password attempt never happens in the first place. The server does not offer the method, the attacker cannot use it, the connection ends earlier. In the log that looks like this:

Invalid user prueba from 160.187.247.119 port 49052
Connection closed by invalid user prueba 160.187.247.119 port 49052 [preauth]

[preauth] means: aborted before any authentication took place.

🔑 That is the actual point: disabling password authentication does not make 26,753 attack attempts harder — it makes them moot. No guessing game that can be won. No password that has to be long enough. The entire attack class disappears. That is fundamentally different from having a good password — and the reason why “keys are more convenient” describes the situation wrongly.

⚠️ Stated honestly: this number proves that this type of attack goes nowhere against us. It does not prove our server is secure. Those 85 successful key logins would be just as successful if a private key fell into the wrong hands. SSH hardening shifts the risk from “guess the password” to “protect the key file” — it does not delete it.

What the attackers are looking for

A look at the usernames guessed over the last seven days shows just how automated this is:

UsernameAttempts
admin601
ubuntu256
wallet145
user131
crypto131
bitcoin110
test107
blockchain86
ec2-user77
centos71

Three of the ten most frequent names — wallet, crypto, bitcoin, plus blockchain — target cryptocurrency software. These are not targeted attacks on us but blanket sweeps of the entire internet looking for worthwhile targets. Further down the list, however, were heynyx (69 attempts) and praxisfix (49) — two names derived from our own domains. Those appear in public certificate transparency logs. Anyone running a domain with HTTPS is handing over username candidates along with it — a detail we documented in more depth in our guide to setting up a Linux server.

The distribution across days is also anything but even:

DayFailed attempts
09 Sep1,156
10 Sep6,926
11 Sep4,828
12 Sep1,554
13 Sep1,179
14 Sep1,498

10 September carries six times the volume of the previous day. Attack load arrives in waves, not as constant background noise — which matters when interpreting any single snapshot.

Thousands of tiny red probing lights converging on a single sealed glowing gateway

Which key type should you use?

The answer is short: Ed25519. The command:

ssh-keygen -t ed25519 -C "laptop-2026"

Ed25519 is based on Curve25519 cryptography, produces very short keys, is fast, and is considered robust against several implementation pitfalls that historically made RSA vulnerable. All four keys registered on our server are Ed25519:

256 SHA256:9y//ran6kYeH… root@Nyx (ED25519)
256 SHA256:mDBO/DgtbDcA… konta@FaBudde (ED25519)
256 SHA256:IMuoPt8+Szqm… kiro@helsinki (ED25519)
256 SHA256:nm9B0YsIB2x5… fabian-handy-laptop-2026 (ED25519)

RSA still works but should be at least 3072 bits (our server still keeps an RSA host key around for compatibility). ECDSA is not broken but unpopular, because its curves trace back to NIST specifications and signature generation is sensitive to poor random numbers. DSA is dead — OpenSSH removed support in version 9.8 (2024).

The most important addition is independent of the type: set a passphrase. A private key without a passphrase is a file that works immediately the moment someone copies it. With a passphrase it is additionally encrypted. And so that you do not have to type it on every connection, there is ssh-agent, which keeps the decrypted key in memory for the duration of your session:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

The key comment is a claim, the log is the proof

This section exists because we learned it from a near-mistake of our own.

At the end of every public key there is a comment — above, for example, kiro@helsinki or fabian-handy-laptop-2026. By default, ssh-keygen puts user@hostname there. It therefore looks like a reliable statement about who owns the key.

It is not. The field is free text. It is set at generation time, verified by nobody, and can be changed at any moment without changing the key itself. The comment tells you what someone was thinking when they generated it — not who owns or uses the key today.

What the comment does not tell you, the log does. OpenSSH records the fingerprint of the key used on every successful login. That lets you check every registered key against reality:

# Fingerprints of all registered keys
ssh-keygen -lf ~/.ssh/authorized_keys

# Who actually used this key — and from where?
journalctl -u ssh --no-pager | grep <FINGERPRINT> \
  | grep -oE "from ([0-9]{1,3}\.){3}[0-9]{1,3}" | sort | uniq -c

For our four keys that produced:

CommentLoginsSource IPs
root@Nyx0
konta@FaBudde0
kiro@helsinki68exactly one (89.167.100.117)
fabian-handy-laptop-202617five rotating residential lines

Two of the four keys were never used across the entire journal window. And the two that were used show a revealing pattern: the key with helsinki in its name does indeed come exclusively from one fixed server IP — that fits. The key with handy-laptop in its name comes from five different IP addresses, exactly as you would expect from a mobile device on changing connections — that fits too.

🔑 The lesson: source IP is possession, the comment is intent. Anyone about to delete an SSH access should check the log rather than trust the name field. A rarely used key may be attached to a silent cron job whose failure only surfaces weeks later. And a key with a foreign-sounding comment may still be your own.

⚠️ The limit of this measurement, stated plainly: the journal only reached back 22 days. “Zero logins” here does not mean “never used”, it means “not within this window”. That difference decides between success and outage when removing an access. Anyone cleaning up needs a longer window — or has to establish the absence some other way.

known_hosts: the warning nobody reads

Remember step 3 of the connection setup — the part where the server identifies itself? This is where it becomes important.

The first time you connect to an unknown server, SSH asks:

The authenticity of host 'server.example.com' can't be established.
ED25519 key fingerprint is SHA256:KtZdIhCO3vbjDpSfd/oermLTrfODaOGjVUc1VyEg0EM.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

Almost everyone types yes. That stores the server’s fingerprint in ~/.ssh/known_hosts. On our client there are 34 entries — in hashed form, so that the file itself does not reveal a list of every server we connect to:

|1|ZeZF6VBOlnAvU0K0R/od3oBUOgI=|6OpraSurwSaqN8Dl2mwEwE4dAjc=

On every subsequent connection your client compares the presented host key against the stored one. If they do not match, you get the message many people reflexively clear away:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!      @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

The usual response is to delete the old entry (ssh-keygen -R server) and carry on. Most of the time that is even correct — the server was rebuilt, the IP reassigned, the host key pair regenerated.

But this warning is the only thing standing between you and a man-in-the-middle attack. Encryption alone does not protect against it: someone who inserts themselves into the connection simply builds two encrypted connections — one to you, one to the real server — and reads everything in the middle. What they lack is the real server’s private host key. That is why the fingerprint changes. That is what the warning is for.

The practical advice: if you know why the key changed (you just reinstalled the server), delete the entry. If you do not know, verify the new fingerprint through a different channel — from your hosting provider’s console, or directly on the server with:

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

~/.ssh/config: the most underrated part

Most SSH users spend years typing long commands with -p, -i and usernames. Meanwhile there is a configuration file that captures all of it once and for all: ~/.ssh/config.

From ours:

Host pastaclean-new
    HostName 128.140.88.82
    Port 52200
    User root
    IdentityFile ~/.ssh/id_ed25519

Instead of ssh -p 52200 -i ~/.ssh/id_ed25519 root@128.140.88.82, ssh pastaclean-new is enough afterwards. That is not only shorter, it is also less error-prone: the correct key is selected automatically instead of the client offering every available key in turn (which with more than six keys can produce Too many authentication failures even though the right one was among them).

An isometric depiction of a workstation connected by orderly glowing links to several servers

A few settings that noticeably change daily work:

Host *
    # Reuse connections instead of rebuilding them every time
    ControlMaster auto
    ControlPath ~/.ssh/cm-%r@%h:%p
    ControlPersist 10m

    # Keep the connection alive, detect dead ones
    ServerAliveInterval 30
    ServerAliveCountMax 3

    # Offer only the key explicitly specified
    IdentitiesOnly yes

ControlMaster is the setting with the largest measurable effect. We measured 190 milliseconds per connection setup above. With a reused connection the entire key exchange falls away — for a deploy script with twenty consecutive SSH calls that is almost four seconds that simply vanish.

ProxyJump also solves the bastion host problem elegantly:

Host internal
    HostName 10.0.0.5
    ProxyJump bastion

With that, ssh internal connects you to a machine that is not reachable from the internet at all — the hop through the bastion host happens automatically and without your private key ever landing on the jump server.

Port forwarding: SSH as a tunnel

SSH can carry more than a command line. It can route arbitrary TCP connections through its encrypted channel. This is one of its most useful and least understood features.

Abstract depiction of a tunnel carrying glowing data pods from a laptop through a fortified wall into a private server cluster

Local forwarding (-L) — brings a service from the server to you:

ssh -L 8080:127.0.0.1:5432 server

Afterwards you reach, at localhost:8080 on your machine, the PostgreSQL database that only listens on 127.0.0.1 on the server. The database port does not need to be opened to the internet for this — and that is exactly the point. Our article on IT security vulnerabilities documents the reason behind this rule: a Docker container with the default mapping 5432:5432 binds to all interfaces and makes the database publicly reachable. The correct form is 127.0.0.1:5432:5432 — with outside access then going through an SSH tunnel.

Remote forwarding (-R) — brings a service from you to the server:

ssh -R 9000:localhost:3000 server

Dynamic forwarding (-D) — turns SSH into a SOCKS proxy:

ssh -D 1080 server

After that, any application that speaks SOCKS5 can route its traffic through the server. This is not a VPN — it only routes what the application explicitly sends through it — but for individual programs it is often exactly right.

Agent forwarding (-A) deserves a warning. It forwards your local key agent to the server so you can connect onwards from there. Convenient — but anyone with root on the intermediate server can use your agent for as long as the connection is open. Use ProxyJump instead, which solves the same problem without handing over your agent.

Abstract visualisation of a cryptographic handshake between two glowing nodes

Common error messages in plain language

Permission denied (publickey) — The server only accepts keys, and yours did not match. Most common causes: wrong username, the public key is not in authorized_keys, or the client offered a different key. ssh -v shows which one was tried in the Offering public key: line.

Host key verification failed — The stored fingerprint does not match the presented one. See the known_hosts section — do not blindly clear it with ssh-keygen -R; understand why first.

Too many authentication failures — Your client offered too many keys in a row and the server gave up after MaxAuthTries (ours: 6). Fix: IdentitiesOnly yes plus an explicit IdentityFile.

WARNING: UNPROTECTED PRIVATE KEY FILE! — Your key file is readable by other users. chmod 600 ~/.ssh/id_ed25519 fixes it. SSH deliberately refuses service here rather than merely warning.

Connection closed by … [preauth] — The connection ended before any login took place. In your own logs this is almost always a bot. Of the 26,753 entries of this kind in our journal, not a single one was a genuine login attempt by a human.

kex_exchange_identification: Connection closed by remote host — Often a fail2ban or firewall that blocked your IP before any negotiation happened.

The five settings that actually matter

In /etc/ssh/sshd_config (or a file under /etc/ssh/sshd_config.d/):

PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
PubkeyAuthentication yes
MaxAuthTries 3

The first line is the one that made 26,753 attacks moot in our measurement. The second closes a bypass many guides forget: without it, the password prompt can return via the keyboard-interactive method even though PasswordAuthentication no is set.

⚠️ Before you disable password authentication, verify in a second session that your key works. Check and reload the configuration:

sshd -t                      # syntax check, reports errors without restarting
systemctl reload ssh

What the actually active configuration is — not what the file says, but what the service really applies — is shown by:

sshd -T | grep -iE "passwordauth|permitroot|pubkeyauth|maxauthtries"

This distinction matters more than it sounds. A setting can be present in the file and still have no effect — for instance because it sits after a Match block or is overridden by an included file. sshd -T asks the service, not the text.

What is not a security gain: moving the port away from 22. It substantially reduces log noise — but that is all. A port scan finds the new port in seconds. If you do it, do it for the quiet logs, not for the security.

Frequently asked questions about SSH

What is SSH in simple terms?

SSH (Secure Shell) is a protocol that lets you log into a remote computer over an untrusted network and work there with everything encrypted. All traffic between your machine and the server is encrypted and protected against modification. On top of that, both sides verify each other’s identity: the server verifies you, and your client verifies that the server is the same one as last time.

What do you need SSH for?

Primarily for administering servers that have no graphical interface — web servers, databases, container hosts. Also for file transfer (scp, sftp, rsync over SSH), for Git access to repositories, for automated deployments, and as a tunnel to reach services that deliberately are not exposed to the internet.

Is SSH secure?

The protocol itself is considered secure when a current version is used. Current OpenSSH versions have used a hybrid post-quantum key exchange by default since version 9.0. The practical risks nearly always lie elsewhere: weak passwords, unprotected private keys, and dismissed host key warnings. Disabling password authentication removes the most common attack type entirely — in our journal it caused 26,753 attempts to go nowhere.

What is the difference between an SSH key and a password?

With a password you transmit the secret itself to the server; it gets to see it. With a key you transmit only a proof that you possess the secret — the private key never leaves your machine. That is why a compromised or spoofed server can harvest a password but not a private key. This is not a comfort question but a different security model.

Which SSH key type should I use?

Ed25519, generated with ssh-keygen -t ed25519. It is short, fast and robust. RSA still works but should then be at least 3072 bits. ECDSA is unpopular, and DSA was removed by OpenSSH in version 9.8 in 2024. More important than the type is a passphrase on the private key plus ssh-agent so you do not have to type it constantly.

What does “Host key verification failed” mean?

The server’s fingerprint no longer matches the one your client stored in ~/.ssh/known_hosts. Usually the cause is harmless: the server was rebuilt or the IP address reassigned. But it can also be a man-in-the-middle attack. If you do not know the reason, verify the new fingerprint through a second channel before deleting the old entry with ssh-keygen -R.

Should I change the SSH port away from 22?

It noticeably reduces the volume of bot requests in your logs, but barely improves security — a port scan finds any port in seconds. As an argument for less log noise it is fine; as a security measure it is not. Disabling password authentication achieves orders of magnitude more.

What is SSH port forwarding?

The ability to route arbitrary TCP connections through the encrypted SSH channel. With -L you pull a service from the server onto your machine (a database listening only locally, for example), with -R you do the reverse and expose a local service on the server, and with -D SSH becomes a SOCKS proxy. This is how you reach services that are deliberately not opened to the internet.

Conclusion

SSH is the way into practically every server that serves anything anywhere. What gets underestimated most is not the encryption — that runs automatically and, with current versions, is already braced against future quantum computers. What gets underestimated are the two places where a human decides.

The first is the choice between key and password. It is usually presented as a convenience question and is in truth a decision about whether an entire attack class exists or not. 26,753 attempts, 2,874 IP addresses, 22 days — and zero failed password attempts, because there was no password to guess.

The second is the host key warning. It looks like an obstacle and is the only protection against an attack that encryption alone cannot fend off.

And a third lesson this article taught us about ourselves: a key comment is a claim, a login log is proof. Two of the four keys registered on our server were not used a single time in 22 days. Had we tidied up by the name field instead of by source IP, we would probably have deleted the wrong one.

If you want to go further from here: our guide to setting up a Linux server walks through hardening step by step with firewall and fail2ban, IT security vulnerabilities places SSH within the larger attack classes, and how our server was hijacked for five days shows what happens when the break-in does not come through SSH at all. If you are still choosing a distribution, Debian vs. Ubuntu covers the differences, and What is a reverse proxy explains the second building block running on almost every one of these servers.