How I Finally gained a surface level intuition of how the web works (By Building a primitive Backend)
When people say “learn how the web works,” it usually sounds abstract — DNS, client–server model, HTTP requests, ports — a bunch of terms that don’t really click until something breaks. Instead of just reading about it, I decided to set up a real Ubuntu virtual machine, run a backend server on it, and connect to it from my own computer. Along the way, I hit firewall issues, port forwarding problems, and confusing network errors — and that’s exactly when everything started to make sense. This post is a hands-on walkthrough of how I finally understood how the web actually works by building and debugging a real client–server setup.
Setup Overview
To understand how the web actually works in practice, I created a small, local client–server environment that mirrors how real backend systems operate in production — just on my own machine. The setup looked like this:
Host machine (Client):
My Windows laptop, acting as the client making HTTP requests usingcurland SSH.Virtual machine (Server):
An Ubuntu VM running inside VirtualBox, acting as the backend server.Networking:
The VM was configured using NAT with port forwarding, so requests from my Windows machine could reach services running inside the VM (similar to how traffic reaches servers behind NAT or load balancers in the cloud).Backend service:
A simple Python HTTP server running on the VM to simulate a backend API/server.-
Access method:
- SSH into the VM to manage the server
- HTTP requests from Windows to the VM to simulate real client–server communication
Client (Windows)
|
| HTTP request (curl / browser)
v
VirtualBox NAT (port forwarding)
|
v
Ubuntu VM (Python backend server)
|
v
HTTP response back to client
🎯 Goal
Understand How the web works (DNS + client–server model) by:
running a server on a Ubuntu VM
connecting to it from Windows
- debugging real network + firewall issues
Connected to Ubuntu VM over SSH (Client → Server)
Command (from Windows)
ssh alok@localhost -p 2222
📌 What this means
Windows = client
Ubuntu VM = server
Port forwarding:
Windows:2222 → VM:22
🧠 New thing I noticed
Last login: ... from 10.0.2.2
✅ Why that happened
VirtualBox NAT hides your real IP
VM sees the NAT gateway (
10.0.2.2)This is how real servers behave behind NAT/load balancers (like on AWS)
2️⃣ Started a web server on the VM (Become the Server)
✅ Command (on VM)
python3 -m http.server 8000 --bind 0.0.0.0
🧠 What this did
Started an HTTP server
Listening on:
0.0.0.0:8000
- 0.0.0.0 = accept connections from outside the VM
3️⃣ First attempt to access from Windows failed
❌ Command (on Windows)
curl http://localhost:8000
❌ Error
Unable to connect to the remote server
🧠 Root cause
Even though:
Server was running ✅
Port forwarding was set ✅
The VM firewall (ufw) was blocking port 8000
4️⃣ Checked firewall (Found the real problem)
✅ Command (on VM)
sudo ufw status
📌 Output (important part)
Status: active
OpenSSH ALLOW
22 ALLOW
3999 ALLOW
🧠 What this means
Port 8000 was NOT allowed
- So Windows → VM:8000 was blocked
5️⃣ Fixed firewall (Opened port 8000)
✅ Commands (on VM)
sudo ufw allow 8000/tcp
sudo ufw reload
✅ Verified
sudo ufw status
Now shows:
8000/tcp ALLOW Anywhere
6️⃣Verified server was running (Correct diagnosis)
✅ Command
sudo ss -tulnp | grep 8000
Output
tcp LISTEN 0.0.0.0:8000 users:(("python3",pid=1989))
Meaning
Python server is alive
Listening on port 8000
Accepting external connections
- No need to restart it
7️⃣Final success: Windows → VM HTTP request worked 🎉
✅ Command (on Windows)
curl.exe http://localhost:8000
✅ Output
<h1>Hello from my backend server 👋</h1>
<p>This response came from my Ubuntu VM.</p>
🗺 Final working network flow
Windows (Client)
↓ curl http://localhost:8000
VirtualBox NAT (port forwarding)
↓
Ubuntu VM (Server)
↓
Python HTTP Server
↓
HTML response back to Windows
🧠 Core Concepts I Actually Learned (not just memorized)
| Concept | I experienced it |
|---|---|
| Client | Windows using curl
|
| Server | Ubuntu VM running Python |
| HTTP | Requests + responses |
| Ports | 22 (SSH), 8000 (web server) |
| DNS | Earlier with dig google.com
|
| NAT |
10.0.2.2 hiding your real IP |
| Firewall |
ufw blocking then allowing 8000 |
| Binding |
0.0.0.0 vs localhost
|
| Infra debugging | App was fine, network blocked |
| Real-world behavior | Same as cloud servers on AWS |
🏁 Big takeaway
I didn’t just “learn how the web works.”
I debugged real backend infrastructure problems:
Server running but unreachable
Firewall blocking traffic
NAT hiding client IP
Port already in use
Binding to correct network interface
Top comments (0)