- What SSH is and why it exists
- How SSH works inside: three layers
- Encryption in SSH: keys, session and fingerprints
- Key-based authentication: public and private
- SSH tunnels and port forwarding
- What SSH is used for in the real world
- SSH vs Telnet: why Telnet is no longer used
- A short history of SSH and OpenSSH
- SSH clients: OpenSSH and alternatives
- SSH security best practices
- Common mistakes when using SSH
- Frequently asked questions
- The bottom line
In 1995, somebody was capturing passwords on the network at the University of Helsinki, reading them straight off the wire while students and staff typed into Telnet and rlogin and handed their credentials over in plain text. Tatu Ylönen looked at what that meant for every login on that network and he wrote code. That code grew into SSH. Today you type a command, hit enter, and a shell opens on a machine on the other side of the planet. That small pause between your enter key and the prompt is where this story lives.
SSH (Secure Shell) is a network protocol that lets you reach another machine and work on it, run commands, move files, publish services, across a network you do not control, such as the internet. Everything that travels between the client and the server is encrypted, and both ends prove who they are before anything is allowed through. It is the modern replacement for Telnet and FTP, and for years it has been the de facto standard for administering servers from the command line.
Here is my thesis, and it is short. SSH is the piece that made remote work possible without handing your credentials to whoever happens to be listening. Understand what it encrypts, how it authenticates you, and what keys and tunnels are really for, and a black box turns into a tool you can configure with judgement, audit on purpose and break deliberately when the situation calls for it. Like almost everything that holds the internet together, it also carries a curious history and a handful of standards worth knowing by name.
What SSH is and why it exists
SSH stands for Secure Shell. Its original purpose was narrow and urgent: replace Telnet and rlogin, which sent the user’s password and the rest of the session in plain text. Anyone sitting in the middle of the network could read the whole conversation. A colleague on the same local network, an operator at the provider, an attacker on a Wi-Fi hotspot, all of them with a front-row seat. SSH was born in 1995 to close that door without giving up the convenience of working from a terminal.
Technically it is a network protocol, not a program you install and double-click. It defines the messages, the algorithms and the negotiation rules, and that is exactly why different implementations can talk to one another. The most widespread is OpenSSH, present by default on practically every Linux system, on macOS and on recent versions of Windows. Others exist (Bitvise on Windows, SSH servers built into network gear, libraries for programming languages). On Windows the best-known client is PuTTY, but the common language is set by the standard, not by any single vendor.
Its essential traits are worth fixing in your head before we go deeper:
- It is operating-system agnostic. It grew up in the Unix world, but today it connects Linux, macOS, Windows and network devices with the same syntax.
- It uses TCP port 22 by default. That number is documented in the standard itself and can be changed, although doing so is not the powerful security measure people often assume. More on that in the best-practices section.
- It authenticates both ends. The server proves who it is to the client, and the client proves who it is to the server. Having the server identify itself too is what stops someone from sitting in the middle and impersonating it.
- It encrypts the entire session, whether you are running commands, transferring files or opening a tunnel between ports.
The architecture of the protocol is described in IETF RFC 4251, which is the primary reference if you want to go into detail. It is short and surprisingly readable, and if you have never opened an RFC, this is a good one to start with.
How SSH works inside: three layers
SSH is organised into three layers stacked one on top of another. Knowing how to tell them apart explains why an authentication failure is not the same as a network failure, and why changing the encryption algorithm has no effect on how users are identified. When something breaks at two in the morning, that distinction is the difference between fixing it in five minutes and losing the night.
1. The transport layer
This is the foundation. It handles the initial key exchange, the encryption of all traffic, checking the integrity of messages and identifying the server. It is defined in RFC 4253. When you open a connection, this layer negotiates which algorithms both ends will use: key exchange, symmetric encryption, integrity (MAC) and compression. If there is no shared set of algorithms, the connection never comes up. You will see the negotiation fail before any password is ever typed.
2. The user authentication layer
On top of the now-encrypted channel, the client proves who it is. This is where passwords, public/private keys, interactive keyboard authentication and variants such as trusted certificates come in. It is RFC 4252. An important point: authentication data travels inside the encrypted tunnel built by the layer below, never before encryption exists. That ordering is the whole reason the sniffing attack from 1995 stops working.
3. The connection layer
Once authenticated, the client can open several logical «channels» over the same session: an interactive shell, a one-off command, a file-transfer process, a port forward. This is what RFC 4254 describes. The fact that channels are independent is the reason you can have a console, a tunnel to a database and an SFTP transfer inside one and the same SSH connection.
OpenSSH adds a very practical feature on top of these layers: connection multiplexing. With ControlMaster and ControlPath, the first connection opens the encrypted channel and later connections reuse it, so a fresh ssh or scp starts instantly instead of repeating the whole handshake and authentication. It is a blessing when you run dozens of commands against the same server. Once you try it, you will not want to go back.
Encryption in SSH: keys, session and fingerprints
The word «encryption» hides three different mechanisms here that work together. Confusing them is the source of a lot of doubt, so let’s take them one at a time.
The session key and forward secrecy
SSH does not encrypt the whole conversation with a single eternal key. At the start, client and server perform a key exchange (usually Diffie-Hellman, in its elliptic-curve variant) from which both derive an ephemeral session key. That key is used for symmetric encryption, which is fast, and is discarded when the connection closes.
The practical consequence is so-called forward secrecy: even if someone records all the traffic today and years later gets hold of the server’s private key, they will not be able to decrypt this particular session, because the ephemeral key is already gone. The curve25519-sha256 algorithm is now the default in modern implementations. Its definition is in RFC 8731.
Symmetric encryption and integrity
To encrypt the data, the session key is already there. The ciphers in common use today are [email protected] and the AES variants in GCM mode (authenticated encryption, which also guarantees the integrity of the message). On top of that, every packet carries an authentication code (MAC) that detects any tampering. If someone tries to alter a single byte along the way, the connection drops. You don’t choose any of this by hand unless you want to fine-tune hardening. OpenSSH ships with a sensible list of preferences out of the box, and for most teams that list is already good enough.
Host keys, fingerprints and the known_hosts file
Before authenticating you, the client checks that the server is who it claims to be. For that the server has a host key (ideally of the Ed25519 type), a public one, which it hands to the client. The first time you connect to a machine, your client stores that key in known_hosts and shows you its fingerprint so you can verify it against a trusted channel. On later connections, if the key does not match, SSH raises an alarm: either the server has been reinstalled, or someone is in the middle.
That warning is exactly the defence against the man in the middle attack I mentioned at the start. Hammering «yes» without looking is one of the most expensive and easiest mistakes to make. Verify the fingerprint through a different channel the first time, and the warning will keep protecting you for years.
Key-based authentication: public and private
Here is the difference that adds the most day-to-day security. Instead of proving who you are by sending a password the server knows, SSH can prove it with a key pair: a private one, which never leaves your machine, and a public one, which you copy to the server.
The mechanics are the usual ones in asymmetric cryptography. The server holds your public key. When you connect, it throws you a challenge. You sign it with your private key and it verifies the signature with the public one. The private key never travels, and without it there is no possible signature. That is why, if your laptop is stolen and you have protected the key with a passphrase, the attacker cannot use it directly.
The typical flow, in practice:
# 1. Generate the key pair (Ed25519, 100 derivation rounds)
ssh-keygen -t ed25519 -a 100 -C "ana@laptop"
# 2. Copy the PUBLIC key to the server
ssh-copy-id -i ~/.ssh/id_ed25519.pub ana@server
# 3. Connect (no password now, but with a local passphrase)
ssh ana@server
Three ideas are worth fixing in place:
- What you copy to the server is the public key. The private one (
~/.ssh/id_ed25519) does not move, is never shared, and is protected with strict permissions (chmod 600). - The passphrase protects the key at rest, not the connection. You enter it once per session and then
ssh-agentmanages it, keeping it in memory so you don’t have to repeat it. - Ed25519 is the recommended choice for new keys: it is compact, fast and its use in SSH is standardised in RFC 8709. RSA is still valid if you need compatibility with older systems, but with long keys.
On the server side, your public keys live in ~/.ssh/authorized_keys, one per line. Permissions matter here. If the directory or the file is group- or world-writable, OpenSSH refuses to use it, because a key that anyone can edit is no guarantee of anything. And when you manage many hosts, the ~/.ssh/config file saves you from repeating the user, the port and the jump host on every command. Ten minutes spent writing that file pays for itself the first week.
In environments with many machines, managing hundreds of authorised keys by hand becomes unsustainable. That is what SSH certificates are for: a trusted authority signs keys and the server accepts anyone presenting a valid certificate, with an expiry date and permissions. It is the same model web certificates use, applied to access keys. And don’t forget that authentication runs one step ahead of authorisation: knowing who you are does not decide what you can do. That second half is handled with permissions, sudo and models such as role-based access control.
SSH tunnels and port forwarding
This is where SSH stops being «a terminal client» and becomes a Swiss army knife. The connection layer can carry any TCP stream between two points, and commands are just one of the things you can push through it. That is called an SSH tunnel, or port forwarding, and it lets you wrap traffic from other protocols inside an encrypted, authenticated connection.
There are three modes worth telling apart, because they get mixed up all the time:
| Type | Option | What it does | Example use |
|---|---|---|---|
| Local forwarding | ssh -L |
Opens a port on your machine and connects it to a destination as seen from the server. | Reaching an internal database that is not exposed to the internet. |
| Remote forwarding | ssh -R |
Opens a port on the server and connects it to a destination as seen from your machine. | Publishing a local service so someone outside can reach it. |
| Dynamic forwarding | ssh -D |
Raises a SOCKS proxy on your machine and routes every connection through the server. | Browsing as if you were on the server’s network, without configuring each service. |
In practice they look like this:
# Local forwarding: port 8080 on my machine points to port 80 on the server
ssh -L 8080:localhost:80 ana@server
# Remote forwarding: port 9000 on the server points to port 3000 on my machine
ssh -R 9000:localhost:3000 ana@server
# Local SOCKS5 proxy on port 1080
ssh -D 1080 ana@server
To administer machines that are not directly reachable, the cleanest option today is ProxyJump, which chains the connection through an intermediate host, the bastion or jump host, without having to open tunnels by hand. You write it in the ~/.ssh/config file:
Host bastion
HostName bastion.example.com
User ana
Host internal
HostName 10.0.0.20
User ana
ProxyJump bastion
A tunnel that is well understood is a working tool. Used badly, it is a security hole. Forwarding ports opens paths the firewall does not see, and agent forwarding (ForwardAgent) can let someone on the server use your keys to jump to other systems. That is why tunnels are opened on purpose, closed when you are done, and never left configured «just in case» on a shared machine.
What SSH is used for in the real world
Beyond the textbook remote console, SSH underpins a large part of the operations of any computer system. These are the uses you will genuinely run into:
- Remote server administration. The classic case: logging into a Linux machine and working as if you were sitting in front of it. It is also the way to fire off one-off commands without opening a session:
ssh server "uptime". - File transfer with SFTP and SCP. Both protocols travel over SSH and encrypt the transfer. SFTP is interactive and lets you browse. SCP is a straight copy and very handy in scripts.
- Synchronisation with rsync. rsync uses SSH as its default transport and sends only the changes, which makes it ideal for backups between machines.
- Git over SSH. When you run
git clone git@...you are authenticating with your SSH key, not with a username and password. It is the method most code platforms prefer. - Automation and deployment. Tools such as Ansible, deployment scripts and continuous integration pipelines connect over SSH to install, update and restart services.
- Reaching internal services through tunnels. Databases, admin panels or APIs that are not exposed to the internet are reached through a tunnel via a bastion.
- Hopping between networks. A machine with access to several networks can act as a bridge, and SSH carries the session on top without exposing each hop.
- Containers and development environments. Connecting to a container’s shell, mounting a remote development server or working against a virtual machine usually ends up being an SSH session.
On the command line, those transfers are usually just two utilities:
# Interactive SFTP session: browse, upload, download
sftp ana@server
# Straight copy of a file to the server
scp backup.tar.gz ana@server:/var/backups/
# And the other way round, pulling a log back to your machine
scp ana@server:/var/log/syslog ./syslog-copy
On Windows, the arrival of an official SSH client and server changed the rules: you no longer need a separate program to administer a Windows Server or to connect from it. If you are coming from there, having real Linux alongside helps a lot, and WSL2 is today the most comfortable way to have a Linux environment inside Windows without dual-booting.
SSH vs Telnet: why Telnet is no longer used
Telnet was for years the standard way to connect to a remote machine. Its protocol dates back to 1983 and is described in RFC 854, but it has a design flaw that cannot be patched: it encrypts nothing. Even the password travels in the clear.
The comparison leaves little room for doubt:
| Aspect | SSH | Telnet |
|---|---|---|
| Encryption | Encrypts the whole session | No encryption: plain text |
| Credentials | Never travel in the clear. Keys supported | Username and password visible on the network |
| Server identity | Verifies the host key | Verifies nothing |
| Integrity | Detects packet tampering | No protection |
| Default port | TCP 22 | TCP 23 |
| Authentication | Password, keys, certificates, MFA | Basically username and password |
| Recommended use | The standard for remote access | Only on isolated networks or lab machines |
Telnet survives in very specific niches: debugging a text service, probing a port that does not speak SSH, connecting to old hardware on a closed network. Outside of that, the recommendation is blunt. If you can use SSH, use SSH. NIST’s own server security guide describes encrypted remote access as basic practice and advises against protocols that send credentials unprotected.
A short history of SSH and OpenSSH
SSH was created by Tatu Ylönen in 1995, after his university suffered a password interception on the network. The first version (SSH-1) became popular quickly, but its design carried weaknesses and the software was proprietary: free for personal use, licensed for commercial use. That restriction was the push that led to free alternatives being created.
In December 1999 OpenSSH was born, driven by the OpenBSD team, with Theo de Raadt, Niels Provos, Markus Friedl and Dug Song among those responsible, from the code Ylönen released. The goal was to have a free implementation, compatible with what already existed and without the licensing strings. It ended up becoming the reference implementation in the Unix and Linux world.
Meanwhile, the protocol was thoroughly revised. Version 2 (SSH-2) fixed the flaws of SSH-1 and was standardised at the IETF. RFCs 4250 to 4256, published in 2006, are the basis of what we use today. SSH-1 became obsolete and every serious implementation rejects it. Every few months, on top of that, OpenSSH publishes releases that retire old algorithms. In version 8.8 (2021), SHA-1-based signatures were disabled by default, a good example that a protocol’s security is also maintained by removing what grows old.
SSH clients: OpenSSH and alternatives
An SSH client is the program that opens the connection. Not all of them are good for the same thing, and choosing one or the other depends on the system and the kind of work.
- OpenSSH. The de facto standard on Linux, macOS and BSD, and available on Windows through WSL or the official installation. The good part: it is free, it runs on the command line, it uses the
~/.ssh/configfile and it is the reference the options are documented against. For administration and automation it is the first choice. - PuTTY. A free, very light graphical client for Windows, useful when you don’t want to (or can’t) use a terminal. Its interface is simple and portable, though less powerful than a terminal client.
- Bitvise SSH Client. A Windows client with session management and built-in file transfer. There is an evaluation version and a paid licence.
- SecureCRT. A commercial cross-platform client aimed at enterprise environments, with advanced terminal emulation, script automation and session management.
- ZOC Terminal. A terminal emulator and client for Windows and macOS, with support for several protocols and session recording.
The reasonable choice for almost everyone is OpenSSH by default and a graphical client when working from a Windows desktop where convenience matters. The tool matters less than what it does: verify the server’s fingerprint and use keys instead of passwords.
When something refuses to connect, resist the urge to change options at random. ssh -v, and its more verbose cousins -vv and -vvv, prints the negotiation step by step, which is usually enough to see whether the two ends share no common algorithm, whether the key is being rejected or whether the hostname does not resolve. Reading a handshake once teaches more than a shelf of tutorials.
SSH security best practices
SSH is secure by design, but its default configuration favours compatibility. Hardening it is a bounded task with a big return. These are the measures that actually move the needle, in line with what server administration guides such as NIST SP 800-123 recommend.
1. Disallow direct root access
Nobody logs in as root over SSH. You log in with a normal user and escalate with sudo. That way the attacker needs two steps, and there is a record of who did what.
2. Turn off password authentication
If only keys are accepted, dictionary brute-force attacks stop making sense. It is the measure that most reduces noise in the logs of an exposed server. On a public server you will see the difference the very first night.
3. Use Ed25519 keys with a passphrase and ssh-agent
Modern keys, protected at rest and managed by the agent so you don’t type the passphrase on every connection. For large fleets, SSH certificates instead of loose lists of keys.
4. Limit who can connect
Directives such as AllowUsers or AllowGroups restrict access to specific accounts. Combined with a firewall that only allows SSH from known addresses, they shrink the exposed surface enormously.
5. Add a second factor
For sensitive access, require something beyond the key: a temporary code (TOTP) or a hardware certificate. It is a layer that makes credential theft far harder.
6. Keep the software updated and review the logs
New versions retire weak algorithms and fix bugs. And failed connection attempts are an excellent source of information: a spike of attempts for a user that does not exist is an early sign of an attack. Tools such as fail2ban automate temporary blocking after several failures.
7. Look after your host keys
The server’s host key is its identity. If it changes without warning, every client that trusted it will complain, and rightly so. It should be generated once and kept safe, not baked into a disk image that gets cloned onto twenty machines, and not shipped inside a container. Rotating a host key is possible and sometimes necessary, but it should be a planned operation announced to users, never a surprise. Hashing the entries in known_hosts keeps the file from leaking which servers a client has visited if the laptop is lost.
A reasonable configuration block in /etc/ssh/sshd_config could look like this:
# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
X11Forwarding no
AllowUsers ana luis
LoginGraceTime 30
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
About changing port 22: people do it a lot and it is not wrong, but it is worth understanding what it contributes. It reduces the noise from automated scans. It does not stop a determined attacker from finding the service. It is one more layer of hygiene sitting on top of the real protections, which are keys and a firewall. And if you do change it, document the change or you will end up hunting for it yourself.
After touching the configuration, validate the file before restarting the service, because a syntax error can lock you out of the server, and check the result with sshd -t. To audit which algorithms your server offers, utilities such as ssh -Q cipher list the ones your client supports, and dedicated auditing tools let you see the configuration from the outside.
Common mistakes when using SSH
Almost every scare with SSH comes from the same handful of oversights. These are the ones that repeat the most:
- Accepting the server fingerprint without checking it. Hitting «yes» straight away gives away the protection against the man in the middle attack. Verify it through a different channel.
- Private keys with no passphrase. If the machine is lost, the key can be used as is. The passphrase is the last line of defence.
- Copying the private key between machines. The private key is not shared: generate one per machine, or use certificates.
- Leaving
PermitRootLogin yesand passwords enabled. That is the combination that turns a server into an easy target. - Using
StrictHostKeyChecking=noto «get rid of the warning». That disables precisely the check that protects the server’s identity, and you end up with a warning you have trained yourself to ignore. - Forwarding the SSH agent to machines you don’t trust. Whoever controls that server can use your keys while the session is open. Enable it only when you need it.
- Opening tunnels and leaving them open. A forgotten forward is a door that is still there. Close it when you are done.
- Ignoring the authentication logs. Repeated failed attempts are an early warning. If you don’t look, you won’t find out.
- Confusing authentication with authorisation. Having access to the machine does not mean you can do anything: permissions and
sudodecide that.
There is one more that is easy to overlook because it only bites in production: editing sshd_config and restarting the service on the very session you are connected through. Test the file with sshd -t first, and keep a second open session until you have confirmed that the new configuration still lets you back in.
A bit of context helps calibrate the risk. Most incidents start with a badly stored key, a weak password or a server that is not updated. Cryptanalysis rarely breaks SSH itself. Cryptography usually holds up. Human oversights do not. Concepts such as the difference between an attacker and a researcher, or the role of offensive security, are explained well in what a hacker is and what types exist.
Frequently asked questions
Are SSH and OpenSSH the same thing?
No. SSH is the protocol, the set of rules and standards that describe how a connection is encrypted and authenticated. OpenSSH is one concrete implementation of that protocol, the most widespread one. It is the same difference as between HTTP and a browser: one is the language, the other speaks it.
What port does SSH use?
TCP 22 by default, as the standard records. It can be changed in the server configuration, and doing so reduces the noise from automated scans, but it is no substitute for deeper measures such as disabling passwords or limiting the allowed addresses.
Is it safer to use keys than passwords?
Yes, by a wide margin. A password can be guessed, reused or leaked. A well-protected private key never travels and without it there is no possible signature. That is why the standard recommendation is to allow only keys and disable password authentication.
What happens if I lose the private key?
You lose access by that route. If you have another authorised key or console access, you can get in and generate a new one. If not, you have to recover the server through the provider. Hence the importance of not depending on a single key and of always having an emergency way in.
Can SSH be used to transfer files?
Yes. SFTP and SCP travel over SSH and encrypt the transfer, unlike classic FTP. For copies that repeat, rsync uses SSH as transport and sends only what has changed.
What is an SSH tunnel and what is it for?
It is using an SSH connection to carry traffic from another protocol between two points, in an encrypted and authenticated way. It is useful, for example, to reach an internal database without exposing it to the internet, or to browse through a remote server. It is convenient and powerful, but it opens paths you should close when you are done.
Does SSH work on Windows?
Yes. Modern versions of Windows include an SSH client and server, and you can also use OpenSSH from WSL or graphical clients such as PuTTY. Compatibility with the protocol is complete.
The bottom line
SSH is one of those technologies that works so well it is barely noticed. Behind a simple ssh user@server there are three layers, an exchange of ephemeral keys, an identity check and encryption that protects everything you type. Understanding those pieces is what separates «using SSH» from «using it well».
The ideas worth taking away are few and clear. Use keys instead of passwords. Always verify fingerprints. Protect the private key with a passphrase. Save tunnels for when they genuinely help. The protocol has been proving since 1995 that you can gain convenience without giving up security. You just have to avoid switching off by hand the protections it comes with.
And the next time you type that command and just walk in, think about everything that has just happened underneath: two machines that have never met have agreed on a secret key, identified each other, and are now talking in encrypted form across a network they do not trust.
So do this tonight. Open /etc/ssh/sshd_config, run sshd -t before you change a line, and turn off password authentication. That single change is the one that pays you back every day, and it takes less time than reading this far.