Title: System Design Adventure - 2B

Subtitle: SSH: The Developer's Encrypted Tunnel

Posted by Afsal on 03-Jul-2026

Hi Pythonistas!

Last post we learned how data travels.
TCP. UDP. Packets. Ports.
This post we take all of that.
And see it working in a real tool you use every day.
SSH.

What Is SSH?

Every developer has typed this:

ssh afsal@myserver.com

But what actually happens?

SSH stands for Secure Shell.
It gives you a secure encrypted terminal on a remote machine.
Before SSH there was Telnet.
Same idea - remote terminal access.
But everything was plain text.
Your password. Your commands. Everything.
Anyone on the network could read it.
SSH fixed that in 1995.
Same story as HTTPS fixing HTTP.
Unencrypted protocol → encrypted version.

What SSH Is Used For

Three things:

1. Remote login

ssh afsal@myserver.com


now you're inside that server's terminal

2. File transfer

scp myfile.txt afsal@myserver.com:/home/afsal/

copy file securely to remote server

3. Tunneling

ssh -L 8080:localhost:3000 afsal@myserver.com

# more on this soon

How SSH Authenticates You

Two ways to prove who you are.

Method 1 - Password

Simple.
You type your password.
Server checks it.
Done.
But weak.
Passwords can be brute-forced.
Passwords can be leaked.
Most production servers disable password auth completely.

Method 2 - Public/Private Key

This is what everyone uses in practice.
Same concept as TLS certificates.
You generate a key pair:

ssh-keygen -t ed25519

Two files created:

~/.ssh/id_ed25519      → private key (NEVER share this)
~/.ssh/id_ed25519.pub  → public key  (share freely)

You put your public key on the server:

~/.ssh/authorized_keys

Now when you SSH in:
Your machine  → "I have the private key for this public key"
Server        → "I have that public key in authorized_keys"
Server        → "Prove it"
Your machine  → signs a message with private key
Server        → verifies with public key
Server        → "You're in"
Your private key never leaves your machine.
Server never sees it.
This is public key authentication.

How the SSH Connection Works

Very similar to TLS handshake from Post 1.

Step 1 - TCP Connection

SSH runs over TCP. Port 22.
Remember from Post 2A:
SSH uses TCP because a single missing character in a terminal command could be catastrophic.


rm -rf /tmp/old_files
Becomes with a missing packet:


rm -rf /
Unacceptable. TCP only.

Step 2 - Version Exchange

Client → "SSH-2.0-OpenSSH_8.9"
Server → "SSH-2.0-OpenSSH_8.9"
Both agree on SSH version.

Step 3 - Server Identifies Itself

Server sends its host key.
Like a TLS certificate but simpler.
No Certificate Authority.
First time you connect:
The authenticity of host 'myserver.com' can't be established.

ED25519 key fingerprint is SHA256:xxxxxxxxxxx
Are you sure you want to continue? (yes/no)
You're being asked:
"Do you trust this server?"
Say yes — fingerprint saved in:
~/.ssh/known_hosts
Next time — SSH checks automatically.
If fingerprint changed:
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
This means:
either the server changed its key
 or someone is intercepting your connection.
SSH's version of certificate verification.

Step 4 - Key Exchange

Same Diffie-Hellman idea as TLS.
Both sides derive a shared Session Key.
Without sending it directly.

Step 5 Authentication

Encrypted tunnel now exists.
Inside that tunnel:
server asks you to prove your identity.
Password or public key auth happens here.

Step 6 - Shell Opens

Authentication passed.
Server opens a shell.
You're in.

SSH vs TLS

They look similar. Different purposes.

TLS                        SSH
──────────────────────────────────────────
Encrypts data in transit   Encrypts + gives you a shell
Used by HTTP, databases    Used for terminal access
Certificate Authorities    No CA verify manually
Runs silently under apps   You use it directly

Same cryptographic foundation:
asymmetric keys     → authentication
Diffie-Hellman      → key exchange
symmetric session   → encrypting data
Different purpose.

SSH Tunneling

This is where SSH gets powerful.
You can forward any port through an SSH connection.

Three types:

Local forwarding   → bring remote port to your machine
Remote forwarding  → expose your local port to remote server
Dynamic forwarding → full SOCKS proxy

Local Port Forwarding

Most common. Used daily.
Syntax:

ssh -L [local_port]:[remote_host]:[remote_port] user@server

Read it as:
"Forward my local_port through the SSH tunnel to remote_host:remote_port"

Example - Access Remote Database

PostgreSQL running on remote server.
Port 5432 not exposed to internet. Good security.
But you need to connect from your laptop.

ssh -L 5432:localhost:5432 afsal@myserver.com

Now connect your database client to:
host: localhost
port: 5432
What actually happens:
Your laptop:5432
      ↓
SSH encrypted tunnel
      ↓
myserver.com:5432 (PostgreSQL)
Your client thinks it's connecting locally.
Actually connecting to the remote database.
Fully encrypted.
Run in background:
bash
ssh -L 5432:localhost:5432 -N -f afsal@myserver.com
-N → no command, just tunnel
-f → go to background
Terminal is free. Tunnel stays open.

Remote Port Forwarding

Opposite direction.
Expose YOUR local port to the remote server.

ssh -R [remote_port]:[local_host]:[local_port] user@server

Example - Share Your Local App

You're building a web app on localhost:3000.
You want to show it to someone.
But you're behind a router. No public IP.

bash

ssh -R 8080:localhost:3000 afsal@myserver.com

Now anyone who accesses:

myserver.com:8080
Gets forwarded to:
your laptop:3000
Your local app accessible publicly.
Without opening your router.
Without a public IP.
This is exactly what ngrok does under the hood.

Dynamic Port Forwarding

Turns SSH into a full SOCKS proxy.

ssh -D 1080 afsal@myserver.com

Configure your browser:
SOCKS proxy: localhost:1080

All browser traffic routes through the remote server.

Your browser
      ↓
localhost:1080
      ↓
SSH tunnel
      ↓
myserver.com sends requests on your behalf

SSH Config File

Typing long commands every day is painful.

Create ~/.ssh/config:

Host myserver
    HostName myserver.com
    User afsal
    IdentityFile ~/.ssh/id_ed25519
    LocalForward 5432 localhost:5432
    LocalForward 6379 localhost:6379


Now just type:
bash
ssh myserver
Connects with your key.
Opens both tunnels automatically.

The Bastion Host Pattern

This is where SSH tunneling meets system design.

In production systems:
Internet
    ↓
Bastion Server     ← only this is public facing
    ↓
Internal network
    ├── App servers
    ├── Databases
    ├── Redis
    └── Internal services
Nothing is exposed directly to the internet.
Everything sits in a private network.
Only the bastion server is public.

To access the database:

ssh -L 5432:prod-db.internal:5432 -N -f deploy@bastion.mycompany.com

Your laptop:5432
      ↓
SSH tunnel to bastion
      ↓
bastion connects to prod-db.internal:5432

Your laptop can't reach the database directly.
Bastion can.
You tunnel through it.
This pattern has a name:
Jump host.
You'll see it everywhere in production infrastructure.
AWS calls it a bastion host.
We'll go deep on this in Future.

Real World Usage

GitHub:

git clone git@github.com:afsal/myrepo.git

That git@github.com that's SSH.
Your public key registered on GitHub.
Every push and pull authenticated via your private key.

Cloud servers:

Every AWS EC2, DigitalOcean droplet uses SSH.
Password auth disabled.
Key-based only.
CI/CD pipelines:
GitHub Actions, GitLab CI use SSH keys to deploy.
Automated. No passwords. Ever.

Mental Model

SSH              → encrypted terminal access to remote machines
Port             → 22
Transport        → TCP always
Auth             → password (weak) or public key (strong)
Host key         → server's identity, saved in known_hosts
Key exchange     → Diffie-Hellman, same as TLS
Session key      → symmetric encryption for the session
Local (-L)       → bring remote port to your machine
Remote (-R)      → expose local port to remote server
Dynamic (-D)     → full SOCKS proxy
-N               → no command, just tunnel
-f               → run in background
Config file      → save everything, one command to connect
Bastion host     → single public server, everything else private

How Everything Connects

Post 1 → TLS handshake
Post 2A → TCP transport
Post 2B → SSH uses both

TLS certificates  ≈ SSH host keys
TLS client certs  ≈ SSH public key auth
HTTPS             = HTTP inside TLS tunnel
SSH               = Shell inside SSH tunnel
Same cryptographic ideas.
Different application.

What Changed for Me

Before this:

SSH was just a command I typed to get into a server.

After this:

I realized SSH is a complete security system 
TCP for reliability,
Diffie-Hellman for key exchange,
public key auth for identity,
encrypted tunnel for everything.
And that tunnel can carry anything not just a shell,
but databases, APIs, entire network traffic.
A single command.
Milliseconds.
You're inside a machine on the other side of the world.
Securely.

What's Coming Next

Now you know how data travels.
How it stays secure in transit.
How developers access systems safely.

DNS - how a name becomes an address.
How parseltongue.co.in becomes an IP.
The phonebook of the internet.