SSH Basics
Network Diagnostics covered how to confirm that a server is reachable, but reachability is not the same thing as control. Running a command, reading a file, or restarting a service on a remote machine requires an actual login session over the network — and in production, an administrator almost never sits down in front of the physical machine. Everything happens remotely, over the network, through SSH (Secure Shell) and its most common implementation, OpenSSH. This article covers what SSH actually does, how the ssh client is used, and how to read the messages it prints on a first connection.
What SSH Solves
Before SSH became standard, the same job was done by Telnet, which sent the login, password, and the entire session in plaintext over the network. Anyone capturing traffic on that network segment — with tcpdump, for instance — could read a password directly off the wire. SSH, introduced in 1995, exists specifically to close that hole: as soon as a connection is established, the traffic is encrypted, so neither the password nor any command that follows is visible on the network.
Today SSH is the base layer for more than interactive login:
- secure file transfer (
scp,sftp,rsync— covered in scp and rsync); - running automated scripts on a remote server, such as a deploy step in a CI/CD pipeline;
- reaching internal services through port forwarding (SSH Tunneling);
- secure access to Git repositories — a
[email protected]:...URL is an SSH connection under the hood.
In practice, "managing a Linux server" almost always means an SSH terminal session to that server.
Client and Server
SSH follows a client-server model:
- the SSH server — a service running on the remote machine, usually
sshd(the OpenSSH server daemon). It listens for incoming connections and, once a user authenticates, gives them a shell or lets them run a command; - the SSH client — the side that initiates the connection, usually the
sshcommand (the OpenSSH client) or a GUI tool such as PuTTY on Windows.
Both sides are provided by the OpenSSH project on most modern distributions — the most widely deployed open-source implementation of the protocol. On Ubuntu/Debian, the client is normally preinstalled, while the server is a separate package:
Checking the service status:
Note
On Ubuntu/Debian the service is normally called ssh; on RHEL-family distributions it's sshd. If you're not sure of the exact name, check with systemctl list-units '*ssh*'.
SSH listens on TCP port 22 by default — a direct continuation of the ports-and-sockets concepts covered earlier in this course. Confirming the server is listening:
0.0.0.0:22 means the service accepts connections on every network interface.
A Short Word on Encryption
An SSH connection layers two independent protections:
- the transport layer — client and server negotiate a shared session key using asymmetric cryptography during what's called the handshake; from that point on, all traffic is protected with symmetric encryption over that key;
- the authentication layer — the user proves their identity, either with a password or — the recommended method — an SSH key pair, covered in depth in SSH Key Authentication.
This article doesn't go into the mathematics of the encryption algorithms themselves. What matters for an administrator is that an SSH session is encrypted end to end, and that network equipment sitting in between cannot read its contents.
Connecting with ssh
The simplest form:
For example:
If the username on the local machine matches the username on the remote server, the user@ part can be dropped:
In that case SSH automatically uses the current local username.
First Connection: the Host Key Prompt
The first time you connect to a given server, a message like this appears:
The authenticity of host '192.168.1.50 (192.168.1.50)' can't be established.
ED25519 key fingerprint is SHA256:k3f9...Qz8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
This is the server presenting its host key — a cryptographic key that identifies it. Since the client has never seen this key before, it asks how it should know this is the genuine server. Answering yes saves the key to ~/.ssh/known_hosts, where it's automatically compared on every later connection. This mechanism is the first layer of defense against man-in-the-middle attacks, and is covered in detail in SSH-Agent and Host Verification.
After that, a password prompt follows (assuming key authentication isn't set up yet):
[email protected]'s password:
Once the correct password is entered, the remote server's shell prompt appears — from that moment, every command runs on that server, not the local machine. To close the session:
or Ctrl+D.
Useful Flags
| Flag | Purpose |
|---|---|
-p <port> |
Connect to a port other than the default 22 |
-l <user> |
Specify the username separately from the user@host form |
-v |
Verbose mode — prints every stage of the connection process (useful for diagnostics) |
-i <file> |
Use a specific private key file instead of the default |
For example, connecting to a server running on port 2222:
ssh -p 2222 [email protected]
Whenever a connection fails, the first diagnostic step is almost always -v (or -vvv for more detail):
ssh -v [email protected]
This shows exactly which stage — the raw TCP connection, host key verification, or authentication — the problem is occurring at.
Running a Single Command Without an Interactive Shell
ssh doesn't have to open a full interactive session. Passing a command as the final argument runs just that one command on the server and returns immediately, printing its output locally:
ssh [email protected] "uptime"
This is the form behind deploy steps, health checks, and monitoring scripts — the "running automated scripts on a remote server" use case from the start of this article. Quote the command so the local shell doesn't interpret it first: without quotes, ssh host echo $HOSTNAME expands $HOSTNAME on the local machine, not the remote one — a classic source of confusion. The later articles in this module lean on this form constantly (ssh prod-web "uptime", ssh alice@server "sudo -l").
Practical Scenario: Diagnosing "Connection Refused"
Problem: trying to connect to a newly deployed server with ssh [email protected] produces:
Step 1 — identify the error type: Connection refused means the packet reached the host at the TCP level, but nothing is listening on port 22. This is different from Connection timed out (a network or firewall block) or Could not resolve hostname (a DNS problem) — each points to a different cause.
Step 2 — check the service status on the server itself (if another access path is available):
If the service shows inactive or failed, that's the cause.
Step 3 — start the service and re-check:
Step 4 — reconnect from the client:
ssh -v [email protected]
Step 5 — result: if the -v output now shows the connection being established, followed by an authentication prompt, the problem is solved. If it's still refused, the next candidate cause is a firewall (sudo ufw status) or a wrong port.
Step 6 — document it: record why the service wasn't running (for instance, it wasn't enabled to start automatically right after the package was installed) and confirm enable was applied so it survives the next reboot.
Interview angle
A question worth being ready for: "the client shows Connection refused — what does that tell you that Connection timed out doesn't?" refused confirms the packet reached the host and the TCP stack actively rejected it because nothing is bound to that port — the network path itself is fine. A silent timed out means no response ever came back, which points toward a firewall dropping the traffic, a routing problem, or an unreachable host. Being able to state that distinction immediately, without guessing, is what separates a systematic diagnosis from trial and error.
Common Mistakes
Treating Every Connection Failure as "the Server Is Down"
Connection refused, Connection timed out, and Could not resolve hostname all feel like "it didn't connect," but their causes are completely different: a service that isn't running, a network/firewall block, and a name resolution failure, respectively. Always read the exact error text.
Accepting Host Key Warnings Automatically, out of Habit
If typing yes at every new host key prompt becomes an unthinking reflex, the same reflex fires during an actual man-in-the-middle attack. If you don't know where a fingerprint should be coming from, confirm it with whoever administers that server, over a separate channel.
Relying on Password Authentication Indefinitely
Password login works, but it isn't recommended for production servers — it's exposed to brute-force attempts and requires typing a password on every connection. The key-based authentication covered in the next article is both more secure and more convenient.
Exercises
- Connect to your lab VM with
ssh -v user@server_ipand identify the main stages in the verbose output (TCP connection, host key verification, authentication). - From the output of
sudo ss -tlnp | grep :22, find which process (name and PID) is listening on port 22. - Deliberately stop the SSH service (
sudo systemctl stop ssh), attempt to connect from another terminal, observe the exact error, then restore the service. - Open
~/.ssh/known_hostsand explain the structure of one of its lines (host, key type, the key itself).
Verification criterion: for exercise 3, the connection attempt while the service is stopped must show Connection refused, not a timeout or DNS error — if it shows something else, re-check which service you actually stopped.