open atlas
↑ Back to track
Command line CLI · 09 · 01

SSH basics

ssh opens an encrypted remote shell. The first-connect host-key prompt implements Trust On First Use (TOFU): accept it once, and SSH will alert you if the server identity ever changes. ~/.ssh/config maps aliases to real hosts, users, and ports.

CLI Senior ◷ 25 min
Level
FoundationsJuniorMiddleSenior

Every production task that cannot be done locally — deploying code, inspecting logs, restarting a service, debugging a running process — requires a remote shell. SSH (Secure Shell) is that shell. It encrypts everything between your terminal and the remote host so nothing leaks over the network. But SSH is also opinionated: the first time you connect to a host, it asks you to verify its identity. That prompt is not noise — it is the trust mechanism that protects you from connecting to the wrong machine. Understanding it is the difference between a disciplined operator and one who blindly types “yes” to everything.

By the end of this lesson you will understand the basic ssh user@host invocation, the host-key prompt and what Trust On First Use (TOFU) means, the -p flag for non-standard ports, and how ~/.ssh/config removes the cognitive overhead of remembering flags for every server.

Goal

After this lesson you can open a remote shell with ssh user@host, explain what the host-key fingerprint prompt means and why accepting it is a one-time commitment, connect to a non-default port with -p, and create ~/.ssh/config entries using Host, HostName, User, and Port so you can type ssh prod instead of ssh deploy@server.example -p 2222.

1

ssh user@host opens an encrypted interactive shell on the remote machine. The syntax is simple: user is the Unix account on the remote side; host is a hostname or IP address.

ssh deploy@server.example

SSH negotiates an encrypted channel (using asymmetric crypto for key exchange, symmetric for the bulk data), authenticates you (by password or key — covered in the next lesson), and drops you into a shell on the remote machine. Your terminal input goes across the encrypted channel; the remote output comes back the same way.

ssh deploy@198.51.100.10          # connect by IP
ssh deploy@server.example -p 2222 # non-default port

The default port is 22. When admins change it to reduce automated scanning noise, you pass -p PORT.

2

The host-key prompt implements Trust On First Use (TOFU). The very first time you SSH to a host, you see something like this:

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

This is SSH telling you: “I have never seen this host before. Its public key fingerprint is X. Is that really the machine you want?” If you accept, SSH saves the host’s public key in ~/.ssh/known_hosts. On every future connection it compares the server’s key against the saved one. If they differ, SSH refuses to connect and shows a loud warning — because a mismatch means either the server was rebuilt, or something is intercepting your connection.

The right operational practice: verify the fingerprint out-of-band (from your cloud console, a provisioning system, or a colleague) before typing “yes”. In practice on trusted internal networks this step is often skipped — but for public servers, verifying matters.

3

~/.ssh/known_hosts stores previously trusted host keys. After you accept the prompt, the file grows by one line:

server.example,198.51.100.10 ssh-ed25519 AAAA...base64key...

If the same server is later rebuilt, its host key changes. SSH will then print a prominent warning and refuse to connect:

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

To recover, remove the stale entry with ssh-keygen -R server.example and reconnect. The same warning also fires if something is doing a man-in-the-middle attack — which is why you should never just blindly remove the entry without first confirming the server was legitimately rebuilt.

4

~/.ssh/config eliminates flag repetition. Typing ssh -p 2222 deploy@web01.example.com on every connection is error-prone. The config file maps short aliases to full connection parameters:

Host prod
    HostName web01.example.com
    User     deploy
    Port     2222

Host staging
    HostName 203.0.113.50
    User     deploy
    Port     22

With this config, ssh prod is equivalent to ssh -p 2222 deploy@web01.example.com. The file uses indentation (spaces or tabs — SSH doesn’t care) under each Host block. HostName is the real address (the Host value is just a local alias). User sets the remote username. Port overrides the default 22.

You can also set global defaults before any Host block:

ServerAliveInterval 60
ServerAliveCountMax 3

These two lines send a keepalive packet every 60 seconds — useful to prevent idle connections from being dropped by NAT or firewalls.

5

~/.ssh/config also supports wildcards. A Host * block at the end applies to all connections not matched by earlier blocks:

Host prod
    HostName web01.example.com
    User     deploy
    Port     2222

Host *.example.com
    User     deploy

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

SSH reads the file top to bottom and applies the first matching value for each setting. So prod gets its specific HostName and Port, any other .example.com host gets User deploy, and every connection gets keepalives. This layering lets you avoid repeating the same values across many hosts.

Worked example

Set up ~/.ssh/config for a three-server deployment.

You manage three servers: a production web server, a staging server, and a bastion jump host. Without config you’d type long commands constantly. With config:

Host bastion
    HostName 198.51.100.1
    User     ops
    Port     22

Host prod
    HostName web01.example.com
    User     deploy
    Port     2222
    ProxyJump bastion

Host staging
    HostName 203.0.113.20
    User     deploy
    Port     22
    ProxyJump bastion

ProxyJump bastion routes the prod and staging connections through the bastion host automatically. Now:

ssh prod        # connect to prod via bastion, one command
ssh staging     # connect to staging via bastion
ssh bastion     # connect to the bastion directly

SSH handles the hop transparently. No VPN, no manual tunnels — the config encodes the topology.

Why this works

On macOS, ~/.ssh/config supports an extra directive: UseKeychain yes paired with AddKeysToAgent yes. These integrate SSH keys with the macOS Keychain so you are not prompted for your passphrase on every session restart. On Linux, ssh-agent handles key caching (covered in the next lesson) but it does not persist across reboots — you need to add keys to the agent after each login.

Common mistake

A common mistake: creating ~/.ssh/config with world-readable permissions. SSH will reject the config silently (or with a warning) if the file permissions are too open. The correct permissions are 600 (owner read/write only):

chmod 600 ~/.ssh/config

The same applies to private keys (~/.ssh/id_ed25519) — they must be 600. Public keys (~/.ssh/id_ed25519.pub) and authorized_keys should be 644. SSH is strict about this for good reason: a world-readable private key or config leaks information to every user on the system.

Check yourself
Quiz

You connect to a new server and SSH shows the host-key fingerprint prompt. You type 'yes'. What happens the next time you connect to the same server?

Recap

ssh user@host opens an encrypted remote shell. The first-connect fingerprint prompt is Trust On First Use (TOFU): SSH stores the host’s public key in ~/.ssh/known_hosts and on every future connection verifies it matches — a mismatch triggers a loud warning you should never ignore. -p PORT overrides the default port 22. ~/.ssh/config maps short aliases (prod, staging) to full connection parameters (HostName, User, Port, ProxyJump), eliminating repetition and encoding your infrastructure topology in a single file. Files under ~/.ssh/ must have permissions 600 — SSH enforces this.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 4 done

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.