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
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.