Skip to content

🛠️ 08-04: Building a VPN Tunnel


📌 From Theory to Practice

The previous lessons covered the concepts behind VPNs: what they're for, the IPsec protocol suite, and tunnel vs. transport mode. This lesson walks through what actually happens, conceptually, when you stand up a real VPN tunnel using two of the most common modern tools — OpenVPN and WireGuard — and how traffic ends up flowing through it on a client machine.

Both tools solve the same two problems every VPN must solve (tunneling + protection — see 08-01: VPN Concepts & Types), but they take different approaches to authentication, key exchange, and implementation complexity.


🕳️ The TUN/TAP Virtual Interface

Before looking at either tool, it helps to understand the piece of plumbing both of them (and IPsec-based VPNs too) rely on: the TUN/TAP virtual network interface.

Normally, a network interface has the OS kernel on one end and a physical wire (Ethernet, Wi-Fi) on the other. A TUN/TAP interface is a virtual network interface where the "other end" isn't physical hardware at all — it's a regular user-space program.

  • TUN interfaces operate at Layer 3 (the IP level). A program attached to a TUN interface reads and writes raw IP packets. This is what Layer-3 VPNs are built on.
  • TAP interfaces operate at Layer 2 (the Ethernet level). A program attached to a TAP interface reads and writes full Ethernet frames (including MAC headers), so it can even see things like ARP traffic. This is what Layer-2 VPNs are built on.

The mental model: when the kernel wants to send a packet out through a TUN/TAP interface, instead of putting it on a wire, it hands the packet to whatever user-space program (the VPN client software) is attached to that interface. That program can then do whatever it wants with the packet — most importantly, encrypt it and ship it across the Internet to the other end of the tunnel. When a packet arrives at the other end and gets decrypted, the receiving program writes it back into its TUN/TAP interface, and the local kernel treats it exactly as if it had arrived over a real network link.

💡 This is why VPN software can make remote resources "just work" with ordinary applications: to everything above the TUN/TAP interface — the routing table, the sockets, the applications — the virtual interface looks and behaves like any other network interface.

How a Client Routes Traffic Through the Tunnel

Once the VPN software creates and configures a TUN/TAP interface (assigning it an IP address and bringing it up), the operating system's routing table decides which traffic goes through it. For example:

# Route all traffic destined for the private network through the tunnel interface
ip route add 10.0.8.0/24 dev tun0

Any packet the OS wants to send to 10.0.8.0/24 is now handed to tun0 instead of the physical network interface. The VPN client program reads that packet off tun0, encrypts it, and sends it as the payload of a regular UDP or TCP packet addressed to the VPN server. The VPN server decrypts it, writes the original packet to its own TUN interface, and the server's kernel routes it onward — possibly out onto the real private network — as if it had arrived locally. Return traffic follows the same path in reverse.

💡 This is the essence of IP tunneling: the inner packet (the one being protected) is carried as the payload of an outer packet that both tunnel endpoints understand how to send and receive across the public network — the same wrapping idea covered in 08-03: Tunnel vs. Transport Mode.


🔐 OpenVPN

OpenVPN is a widely deployed, TLS-based VPN implementation. Rather than inventing its own cryptographic handshake, it builds on the same TLS machinery used to secure HTTPS websites (see Module 09), which means it inherits decades of battle-tested cryptographic design.

Key characteristics:

  • Runs over UDP (typically) or TCP, on a configurable port.
  • Uses a TLS handshake to authenticate the client and server and to establish session keys — see 07-08: Digital Certificates & PKI for how certificate-based authentication actually works underneath this.
  • Supports certificate-based mutual authentication: the server presents a certificate, and (in stronger configurations) each client also presents its own client certificate, so both sides cryptographically prove their identity — not just the server.
  • Implemented largely in user space, which makes it flexible and portable but historically a bit heavier/slower than kernel-level alternatives.

Simplified Example Config Snippet

# client.ovpn (simplified, illustrative only)
client
dev tun
proto udp
remote vpn.example.com 1194

# Certificate-based authentication material
ca   ca.crt        # the CA certificate used to verify the server's cert
cert client.crt    # this client's own certificate
key  client.key    # this client's private key (keep secret!)

# Encryption/integrity settings for the data channel
cipher AES-256-GCM
auth   SHA256

The ca, cert, and key lines are the certificate/key-based authentication pieces: the client uses its own certificate and private key to prove its identity, and uses the CA certificate to verify that the server's certificate was issued by a trusted authority. This is the same trust-chain logic used everywhere else PKI is used — full details in 07-08: Digital Certificates & PKI.


⚡ WireGuard

WireGuard is a newer VPN protocol designed to be dramatically simpler and faster than OpenVPN or traditional IPsec, while still being cryptographically strong. Instead of negotiating from a menu of cipher suites (like TLS or IKE do), WireGuard hard-codes a single, modern, carefully chosen set of cryptographic primitives — there's no cipher negotiation at all, which shrinks the attack surface considerably.

Key characteristics:

  • Runs entirely over UDP.
  • Uses public-key authentication instead of certificates: each peer has a static public/private keypair (conceptually similar to an SSH keypair), and peers authenticate each other by trusting the other party's public key directly — there's no certificate authority involved by default.
  • Implemented as a very small, often kernel-level codebase, which makes it fast and easy to audit compared to the much larger OpenVPN/IPsec codebases.
  • Uses modern primitives for its key exchange under the hood, conceptually related to the Diffie-Hellman-style key agreement described in 07-05: Diffie-Hellman Key Exchange — two parties combine their own private key with the other's public key to derive a shared session secret.

Simplified Example Config Snippet

# wg0.conf (simplified, illustrative only)

[Interface]
PrivateKey = <this-device's-private-key>
Address = 10.0.8.2/24

[Peer]
PublicKey  = <server's-public-key>
Endpoint   = vpn.example.com:51820
AllowedIPs = 10.0.8.0/24        # traffic to this range goes through the tunnel

Here, PrivateKey and the peer's PublicKey are the entire authentication mechanism — there's no certificate chain to validate, no CA to trust. Each side just needs to already know the other side's public key (exchanged out-of-band, ahead of time, much like adding a trusted SSH key). AllowedIPs does double duty: it's both a routing instruction (what traffic goes through this tunnel) and a security filter (what source addresses are accepted from this peer).


⚖️ OpenVPN vs. WireGuard, Briefly

Feature OpenVPN WireGuard
Authentication Certificates (PKI), TLS handshake Static public keys, no CA needed
Cipher choice Negotiated (configurable cipher suite) Fixed, modern primitives (no negotiation)
Codebase size Large Very small
Typical performance Good, but more overhead Generally faster, lower overhead
Best fit Environments that already have PKI/certificate infrastructure Simpler point-to-point setups, performance-sensitive scenarios

💡 Neither is "insecure" — both are widely trusted in production today. The practical choice usually comes down to whether you already have (or want) certificate infrastructure to manage, versus a simpler model of manually exchanging public keys between a known, smaller set of peers.


📌 Key Takeaways

  • A TUN/TAP virtual interface is the plumbing that lets a user-space VPN program intercept packets the kernel wants to send, and inject packets the kernel should receive, making a tunnel look like a normal network interface to everything above it.
  • TUN works at Layer 3 (IP packets) for Layer-3 VPNs; TAP works at Layer 2 (Ethernet frames) for Layer-2 VPNs.
  • The client's routing table decides which traffic gets sent to the tunnel interface — that's what makes "route specific traffic through the VPN" possible.
  • OpenVPN builds on TLS and certificate-based (PKI) authentication, giving it strong flexibility and a large trust ecosystem — see 07-08: Digital Certificates & PKI.
  • WireGuard uses static public/private keypairs with no certificate authority, fixed modern cryptography, and a much smaller codebase, favoring simplicity and speed.
  • Both tools ultimately solve the same problem: get a packet from the client's tunnel interface, protect it, deliver it to the server's tunnel interface, and route it onward.
  • Configuration details differ, but the underlying pattern — authenticate, derive session keys, wrap/protect packets, route through a virtual interface — is the same one covered conceptually in earlier Module 08 lessons.