Home CS Fundamentals VPN Explained: How Virtual Private Networks Actually Work

VPN Explained: How Virtual Private Networks Actually Work

In Plain English 🔥
Imagine you need to pass a secret note to a friend across a crowded classroom. Instead of passing it openly where anyone could read it, you put it inside a sealed envelope, write a fake address on the outside, and hand it to a trusted messenger who delivers it privately. A VPN does exactly that for your internet traffic — it wraps your data in an encrypted 'envelope', disguises where it's going, and routes it through a private messenger (the VPN server) so nobody snooping on the network can read it or trace it back to you.
⚡ Quick Answer
Imagine you need to pass a secret note to a friend across a crowded classroom. Instead of passing it openly where anyone could read it, you put it inside a sealed envelope, write a fake address on the outside, and hand it to a trusted messenger who delivers it privately. A VPN does exactly that for your internet traffic — it wraps your data in an encrypted 'envelope', disguises where it's going, and routes it through a private messenger (the VPN server) so nobody snooping on the network can read it or trace it back to you.

Every time you open a browser, your device sends data across the internet like postcards — visible to your internet provider, the café Wi-Fi router, and potentially anyone else sitting on the same network. Most people assume the internet is private. It isn't. Your traffic passes through dozens of routers, any of which can log, inspect, or intercept what you're sending. This matters for everyone — not just activists or hackers — because it affects your banking sessions, your work emails, and the personal searches you'd rather keep personal.

A VPN, or Virtual Private Network, was invented to solve exactly this problem. It creates a private, encrypted tunnel between your device and a server somewhere else on the internet, so that everything flowing through that tunnel is scrambled and unreadable to outsiders. It also masks your real IP address — the digital equivalent of your home address — replacing it with the VPN server's address. This means websites see the VPN server, not you, and anyone spying on your connection sees gibberish instead of your data.

By the end of this article you'll be able to explain what a VPN is and why it exists, describe how tunneling and encryption work together in plain English, know when using a VPN actually helps and when it doesn't, and walk into a technical interview and confidently answer questions about VPN architecture. No networking degree required — we build everything from the ground up.

The Problem VPNs Solve: Why Your Internet Traffic Is Basically a Postcard

When you type a URL into your browser, your device breaks your request into small chunks called packets. Those packets travel from your device → your home router → your Internet Service Provider (ISP) → a chain of routers across the internet → the destination server. Every single hop along that chain can theoretically see what's inside those packets.

Your ISP can legally log every domain you visit. On a public Wi-Fi network — like at a coffee shop — any device on the same network running packet-sniffing software (tools like Wireshark are free and legal) can intercept unencrypted traffic. Advertisers track your real IP address to build a profile of your browsing behaviour. Governments in some countries actively monitor and censor internet traffic.

Now, it's fair to say HTTPS (the padlock you see in your browser) already encrypts the content of most web requests. But HTTPS doesn't hide who you're talking to. Your ISP can still see you connected to example-bank.com at 2 AM. The VPN fixes both problems: it encrypts the content AND hides the destination by routing everything through its own server first.

without_vpn_simulation.py · PYTHON
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
# Simulating what a network observer sees WITH and WITHOUT a VPN
# This is a conceptual model — not real packet capture code
# but it illustrates the exact difference in visibility

import hashlib

def simulate_packet(destination_url: str, payload: str) -> dict:
    """Creates a simplified representation of an internet packet."""
    return {
        "source_ip": "203.0.113.42",      # Your real public IP address
        "destination_ip": "93.184.216.34", # The web server's IP (e.g., example.com)
        "destination_url": destination_url, # Visible to your ISP even with HTTPS
        "payload": payload                  # Content (HTTPS encrypts this, but not the rest)
    }

def simulate_vpn_packet(destination_url: str, payload: str, vpn_server_ip: str) -> dict:
    """Shows what an observer sees when a VPN is active."""
    # The entire original packet (destination + payload) gets encrypted
    original_packet = f"{destination_url}|{payload}"
    
    # hashlib.sha256 here represents encryption — the real data is unreadable
    encrypted_blob = hashlib.sha256(original_packet.encode()).hexdigest()
    
    return {
        "source_ip": "203.0.113.42",  # Your real IP (only the VPN server sees this)
        "destination_ip": vpn_server_ip, # All traffic goes to the VPN server, not the real site
        "destination_url": "HIDDEN",      # ISP cannot see this anymore
        "payload": encrypted_blob         # Looks like random noise to any observer
    }

# --- What your ISP sees WITHOUT a VPN ---
raw_packet = simulate_packet(
    destination_url="my-bank.com/login",
    payload="username=alice&password=hunter2"
)

print("=== WITHOUT VPN (what your ISP/café Wi-Fi sees) ===")
for key, value in raw_packet.items():
    print(f"  {key}: {value}")

print()

# --- What your ISP sees WITH a VPN ---
vpn_packet = simulate_vpn_packet(
    destination_url="my-bank.com/login",
    payload="username=alice&password=hunter2",
    vpn_server_ip="198.51.100.10"  # The VPN provider's server IP
)

print("=== WITH VPN (what your ISP/café Wi-Fi sees) ===")
for key, value in vpn_packet.items():
    print(f"  {key}: {value}")

print()
print("Key insight: With the VPN, your ISP only knows you connected to the VPN server.")
print("It cannot see the real destination or the content — both are encrypted.")
▶ Output
=== WITHOUT VPN (what your ISP/café Wi-Fi sees) ===
source_ip: 203.0.113.42
destination_ip: 93.184.216.34
destination_url: my-bank.com/login
payload: username=alice&password=hunter2

=== WITH VPN (what your ISP/café Wi-Fi sees) ===
source_ip: 203.0.113.42
destination_ip: 198.51.100.10
destination_url: HIDDEN
payload: a3f1c8d2e9b4071f6a2c3e5d8f1b9042a7e3c6d5f8b2094e1a7c3d6f9b2e5a8d1

Key insight: With the VPN, your ISP only knows you connected to the VPN server.
It cannot see the real destination or the content — both are encrypted.
🔥
HTTPS vs VPN — They're Not the Same ThingHTTPS encrypts the *body* of your request (good!), but the destination URL and your IP address are still visible. A VPN encrypts everything including the destination, so your ISP sees only 'this device sent encrypted data to a VPN server' — nothing else.

How a VPN Actually Works: Tunneling, Encryption, and IP Masking Step by Step

A VPN works using three core mechanisms working together: a tunnel, encryption, and IP substitution. Understanding all three is what separates someone who's used a VPN from someone who actually understands networking.

The Tunnel: Think of the public internet as a glass pipe — everyone can see through it. A VPN creates a second, opaque pipe running inside the glass one. Your data travels through the opaque inner pipe, so even though it's using the same physical infrastructure, nobody can see inside it. Technically, this is called encapsulation — your original packet is wrapped inside a new packet, like putting a letter inside another envelope.

Encryption: Before your data enters the tunnel, it's encrypted using algorithms like AES-256 (Advanced Encryption Standard with a 256-bit key). This is military-grade encryption — it would take longer than the age of the universe to brute-force with current computers. Only the VPN server holds the key to decrypt it.

IP Masking: When your encrypted packet arrives at the VPN server, the server decrypts it and forwards the request to the real destination — but the request now appears to come from the VPN server's IP address, not yours. The destination website responds to the VPN server, which re-encrypts the response and sends it back to you. Your real IP address never touches the destination.

vpn_tunnel_simulation.py · PYTHON
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
# Simulating the full VPN tunnel lifecycle
# Encapsulation → Encryption → Transmission → Decryption → Forwarding

from cryptography.fernet import Fernet  # pip install cryptography

# ─────────────────────────────────────────────
# SETUP: VPN client and server share a secret key
# In real VPNs this key exchange uses protocols like TLS or Diffie-Hellman
# ─────────────────────────────────────────────
shared_secret_key = Fernet.generate_key()  # Generates a secure random 256-bit key
cipher = Fernet(shared_secret_key)          # The cipher object handles encrypt/decrypt

print(f"Shared secret key (base64): {shared_secret_key[:20]}...\n")  # Don't print full keys in prod!


def encapsulate_packet(original_payload: str, real_destination: str) -> dict:
    """Step 1 — Wraps the original request in a new packet (tunneling)."""
    inner_packet = f"DEST:{real_destination}|DATA:{original_payload}"
    return {"inner_packet": inner_packet}


def encrypt_packet(encapsulated: dict, cipher_suite: Fernet) -> bytes:
    """Step 2 — Encrypts the inner packet. The output is unreadable without the key."""
    raw_bytes = encapsulated["inner_packet"].encode("utf-8")
    encrypted = cipher_suite.encrypt(raw_bytes)  # AES encryption under the hood
    return encrypted


def transmit_to_vpn_server(encrypted_data: bytes, vpn_server_ip: str) -> dict:
    """Step 3 — Sends encrypted payload to VPN server. Outer packet only shows VPN IP."""
    outer_packet = {
        "visible_destination": vpn_server_ip,  # This is all your ISP sees
        "visible_source": "203.0.113.42",       # Your real IP (VPN server knows this)
        "encrypted_payload": encrypted_data     # Gibberish to any observer
    }
    return outer_packet


def vpn_server_receives(outer_packet: dict, cipher_suite: Fernet) -> tuple:
    """Step 4 — VPN server decrypts the payload and extracts the real destination."""
    decrypted_bytes = cipher_suite.decrypt(outer_packet["encrypted_payload"])
    decrypted_text = decrypted_bytes.decode("utf-8")
    
    # Parse destination and data from decrypted inner packet
    parts = dict(item.split(":", 1) for item in decrypted_text.split("|"))
    real_destination = parts["DEST"]
    original_data = parts["DATA"]
    
    return real_destination, original_data


def forward_request(real_destination: str, data: str, vpn_server_ip: str) -> str:
    """Step 5 — VPN server forwards to real destination. Site only sees VPN server IP."""
    print(f"  VPN server ({vpn_server_ip}) is requesting: {real_destination}")
    print(f"  Original data: {data}")
    print(f"  From destination's perspective — request came from: {vpn_server_ip}")
    return f"Response from {real_destination}: 200 OK, here is your content."


# ─────────────────────────────────────────────
# SIMULATE THE FULL JOURNEY
# ─────────────────────────────────────────────
VPN_SERVER_IP = "198.51.100.10"
USER_REQUEST = "GET /account/balance"
TARGET_SITE = "my-bank.com"

print("--- STEP 1: Encapsulate (wrap original packet) ---")
encapsulated = encapsulate_packet(USER_REQUEST, TARGET_SITE)
print(f"  Inner packet: {encapsulated['inner_packet']}\n")

print("--- STEP 2: Encrypt ---")
encrypted = encrypt_packet(encapsulated, cipher)
print(f"  Encrypted (what ISP sees): {encrypted[:40]}...\n")  # Just a preview

print("--- STEP 3: Transmit to VPN server ---")
outer_packet = transmit_to_vpn_server(encrypted, VPN_SERVER_IP)
print(f"  ISP only sees: {outer_packet['visible_source']} → {outer_packet['visible_destination']}\n")

print("--- STEP 4: VPN server decrypts ---")
destination, payload = vpn_server_receives(outer_packet, cipher)
print(f"  Decrypted destination: {destination}")
print(f"  Decrypted payload: {payload}\n")

print("--- STEP 5: Forward to real destination ---")
response = forward_request(destination, payload, VPN_SERVER_IP)
print(f"\nFinal response received by you: {response}")
▶ Output
Shared secret key (base64): b'gAAAAAB...

--- STEP 1: Encapsulate (wrap original packet) ---
Inner packet: DEST:my-bank.com|DATA:GET /account/balance

--- STEP 2: Encrypt ---
Encrypted (what ISP sees): b'gAAAAABl3kXqP8mN2vQrT7cYwZsA...

--- STEP 3: Transmit to VPN server ---
ISP only sees: 203.0.113.42 → 198.51.100.10

--- STEP 4: VPN server decrypts ---
Decrypted destination: my-bank.com
Decrypted payload: GET /account/balance

--- STEP 5: Forward to real destination ---
VPN server (198.51.100.10) is requesting: my-bank.com
Original data: GET /account/balance
From destination's perspective — request came from: 198.51.100.10

Final response received by you: Response from my-bank.com: 200 OK, here is your content.
⚠️
Pro Tip: AES-256 in Plain EnglishAES-256 means there are 2²⁵⁶ possible keys — that's more than the number of atoms in the observable universe. Even if every computer on Earth worked together trying random keys, it would take billions of times longer than the universe has existed to crack a single message. It's not 'pretty secure' — it's computationally impossible to brute-force.

VPN Protocols Compared: OpenVPN, WireGuard, and IPSec Explained Simply

A VPN protocol is the set of rules that governs how the tunnel is built and how encryption is negotiated. Think of it like a language — both the client and server need to speak the same one. Different protocols make different trade-offs between speed, security, and compatibility.

OpenVPN is the old reliable. It's been around since 2001, is open-source, battle-tested, and works on virtually every platform. It uses TLS (the same tech as HTTPS) for the encryption handshake. The downside: it's complex, slower than modern alternatives, and harder to configure from scratch.

WireGuard is the new kid who showed up and made everyone else look slow. It has only ~4,000 lines of code (OpenVPN has ~100,000), making it far easier to audit for security bugs. It's dramatically faster, uses modern cryptography (ChaCha20, Curve25519), and is now built into the Linux kernel. Most consumer VPNs (NordVPN, Mullvad) have switched to it.

IPSec (with IKEv2) is the enterprise standard — it's built into Windows, macOS, iOS, and Android natively, making it great for corporate VPNs that can't ask employees to install software. Solid, fast, but the configuration is notoriously complex.

wireguard_config_example.conf · BASH
123456789101112131415161718192021222324252627282930313233343536
# WireGuard VPN Configuration FileClient Side
# This is a REAL WireGuard config format used in production.
# Save this as /etc/wireguard/wg0.conf on Linux systems.
# Run: sudo wg-quick up wg0    (to connect)
# Run: sudo wg-quick down wg0  (to disconnect)

[Interface]
# Your device's private key (generated with: wg genkey)
# NEVER share this. Keep it secret. Keep it safe.
PrivateKey = sKmQzT3vXbL9nYqR2pW8eA1fGcH7dJ0iOuN5mKlV4=

# The IP address your device gets INSIDE the VPN tunnel
# 10.0.0.0/8 is a private address range — only exists within the VPN
Address = 10.0.0.2/24

# Use the VPN server as DNS resolver to prevent DNS leaks
# (Without this, DNS queries bypass the VPN — a common security hole)
DNS = 1.1.1.1

[Peer]
# The VPN server's PUBLIC key (safe to share — this is NOT the private key)
PublicKey = GhT4nM7pQrS2dK1aF9oY6bX3cE5wJ8vU0iL2mN4lP=

# AllowedIPs = 0.0.0.0/0 means ALL traffic goes through the VPN
# (This is 'full tunnel' mode — maximum privacy)
# Alternative: list specific IPs to only route certain traffic through VPN
# (That's called 'split tunneling' — useful for performance)
AllowedIPs = 0.0.0.0/0, ::/0

# The VPN server's real public IP address and port
# Port 51820 is WireGuard's default
Endpoint = 198.51.100.10:51820

# Sends a keepalive packet every 25 seconds
# Required if you're behind NAT (like a home router) to keep the tunnel alive
PersistentKeepalive = 25
▶ Output
# When you run: sudo wg-quick up wg0
# You'll see output similar to:
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.0.0.2/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] resolvconf -a tun.wg0 -m 0 -x
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0

# Verify the tunnel is active:
# sudo wg show
interface: wg0
public key: GhT4nM7p...
listening port: 51820

peer: GhT4nM7pQrS2dK1aF9oY6bX3cE5wJ8vU0iL2mN4lP=
endpoint: 198.51.100.10:51820
allowed ips: 0.0.0.0/0, ::/0
latest handshake: 5 seconds ago
transfer: 1.23 MiB received, 456 KiB sent
⚠️
Watch Out: DNS Leaks Kill Your PrivacyIf your WireGuard or OpenVPN config doesn't specify a DNS server, your operating system silently uses your ISP's DNS servers — outside the tunnel. This means your ISP can still see every domain you visit, even with the VPN active. Always set DNS inside your VPN config. Test for leaks at dnsleaktest.com.

When to Use a VPN (and When It Won't Actually Help You)

VPNs are powerful tools, but they're not magic shields. Knowing when a VPN genuinely helps versus when it gives false confidence is what separates informed users from everyone else.

VPN genuinely helps when: - You're on public Wi-Fi (cafés, airports, hotels). These networks are prime hunting grounds for attackers running man-in-the-middle attacks. - You want to prevent your ISP from selling your browsing data (legal in many countries). - You need to access your company's internal resources (intranet, internal APIs) remotely. This is the original use case VPNs were designed for. - You're in a country that censors certain websites and need unrestricted access. - You want the destination website to see a different geographic location (for accessing region-locked content).

VPN does NOT help when: - You're already logged into Google, Facebook, or any account. Those services track you by your account identity, not your IP. Changing your IP doesn't make you anonymous to them. - You want protection from malware or phishing. A VPN encrypts traffic — it doesn't scan it for threats. - The VPN provider itself is malicious or keeps logs. You're just moving trust from your ISP to the VPN provider. A shady VPN is worse than no VPN. - You think it makes you 'anonymous'. It makes you harder to track, not untraceable. Your browser fingerprint, cookies, and account logins still identify you.

vpn_use_case_advisor.py · PYTHON
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
# A simple decision tool that outputs VPN recommendations
# based on a user's situation — demonstrates VPN use cases in code

def assess_vpn_benefit(situation: dict) -> str:
    """
    Evaluates whether a VPN meaningfully helps in a given situation.
    situation: dict with boolean flags describing the user's context.
    Returns a recommendation string.
    """
    benefits = []
    warnings = []
    
    # Scenario 1: Public Wi-Fi is the #1 legitimate use case
    if situation.get("on_public_wifi"):
        benefits.append("✅ Strong benefit: Protects you from snooping on untrusted networks.")
    
    # Scenario 2: ISP data selling — real concern in US, UK, Australia
    if situation.get("worried_about_isp_tracking"):
        benefits.append("✅ Real benefit: ISP can no longer see your browsing destinations.")
    
    # Scenario 3: Remote work / corporate access — the original VPN use case
    if situation.get("accessing_corporate_network"):
        benefits.append("✅ Essential: VPN is the standard way to access private company resources remotely.")
    
    # Scenario 4: Geographic restriction bypass
    if situation.get("want_different_geo_location"):
        benefits.append("✅ Works: VPN server's location appears as your location to websites.")
    
    # Scenario 5: Logged into personal accounts — VPN doesn't help here
    if situation.get("logged_into_google_or_facebook"):
        warnings.append("⚠️  Limited benefit: Google/Facebook track by account, not IP. VPN won't hide your activity from them.")
    
    # Scenario 6: Malware concern — VPN is the wrong tool
    if situation.get("worried_about_malware"):
        warnings.append("❌ Wrong tool: VPNs don't block malware. Use antivirus + uBlock Origin instead.")
    
    # Scenario 7: Untrusted VPN provider
    if situation.get("using_free_vpn_with_no_audit"):
        warnings.append("❌ Danger: Free unaudited VPNs often log and sell your data — worse than no VPN. Use Mullvad, ProtonVPN, or a self-hosted solution.")
    
    output = ["\n=== VPN Benefit Assessment ==="]
    
    if benefits:
        output.append("\n📗 Where a VPN helps you:")
        output.extend(benefits)
    
    if warnings:
        output.append("\n📕 Where a VPN won't (or might hurt):")
        output.extend(warnings)
    
    if not benefits and not warnings:
        output.append("Neutral situation — VPN neither particularly helps nor hurts.")
    
    return "\n".join(output)


# --- Example: Developer working remotely from a café ---
developer_at_cafe = {
    "on_public_wifi": True,
    "worried_about_isp_tracking": True,
    "accessing_corporate_network": True,
    "want_different_geo_location": False,
    "logged_into_google_or_facebook": True,   # Still logged in — VPN won't hide this
    "worried_about_malware": False,
    "using_free_vpn_with_no_audit": False
}

result = assess_vpn_benefit(developer_at_cafe)
print(result)
▶ Output

=== VPN Benefit Assessment ===

📗 Where a VPN helps you:
✅ Strong benefit: Protects you from snooping on untrusted networks.
✅ Real benefit: ISP can no longer see your browsing destinations.
✅ Essential: VPN is the standard way to access private company resources remotely.

📕 Where a VPN won't (or might hurt):
⚠️ Limited benefit: Google/Facebook track by account, not IP. VPN won't hide your activity from them.
🔥
Interview Gold: VPN vs Proxy vs TorInterviewers love this comparison. A proxy only redirects traffic for one app (like a browser) and usually doesn't encrypt. A VPN encrypts ALL traffic from your entire device at the OS level. Tor bounces your traffic through 3+ volunteer nodes for maximum anonymity but is much slower. VPN is the practical middle ground for most real-world use cases.
FeatureNo VPNVPN (WireGuard)Tor Network
Encrypts trafficNo (unless HTTPS)Yes — AES-256 / ChaCha20Yes — 3 layers (onion)
Hides destination from ISPNoYesYes
Speed impactNone5–15% slowdownVery slow (3 hops)
Hides IP from websitesNoYes (shows VPN IP)Yes (shows exit node IP)
Protects from malwareNoNoNo
Works for all appsYesYes (full tunnel)No (browser only by default)
Trust required inYour ISPYour VPN providerNo single party
Best forFast home connectionPublic Wi-Fi, remote workJournalists, activists
Setup complexityNoneLow (consumer apps)Low (Tor Browser)

🎯 Key Takeaways

    ⚠ Common Mistakes to Avoid

    • Mistake 1: Assuming a VPN makes you completely anonymous — Symptom: User is surprised when Google still shows personalised ads after enabling VPN. Fix: Understand that websites track you via cookies, browser fingerprints, and account logins — none of which a VPN touches. A VPN hides your IP; it doesn't wipe your identity. Log out of accounts and use a privacy-focused browser alongside your VPN for meaningful anonymity.
    • Mistake 2: DNS leaking outside the VPN tunnel — Symptom: You're connected to a VPN but dnsleaktest.com shows your real ISP as the DNS resolver. Fix: Explicitly set DNS inside your VPN config (e.g., DNS = 1.1.1.1 in WireGuard, or push 'dhcp-option DNS 1.1.1.1' in OpenVPN). Many consumer VPN apps handle this automatically, but DIY configs almost always miss it.
    • Mistake 3: Using split tunneling carelessly on corporate VPNs — Symptom: You set AllowedIPs to only route work traffic through the VPN, but accidentally route sensitive personal traffic over the unprotected connection, or vice versa — leaking personal browsing to your employer. Fix: Understand exactly which IP ranges or apps are included in split tunneling before enabling it. If in doubt, use full tunnel (AllowedIPs = 0.0.0.0/0) and accept the minor performance hit.

    Interview Questions on This Topic

    • QCan you walk me through what happens at the network layer when a user connects to a VPN — specifically, how does packet encapsulation work and what does each layer of the packet look like before and after encryption?
    • QWhat's the difference between a site-to-site VPN and a remote-access VPN, and when would a company choose one over the other?
    • QIf a user is connected to a VPN but you can still identify them — how is that possible? What are the ways a VPN fails to provide anonymity?
    🔥
    TheCodeForge Editorial Team Verified Author

    Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.

    ← PreviousFirewalls and ProxiesNext →Network Interview Questions
    Forged with 🔥 at TheCodeForge.io — Where Developers Are Forged