← Back to list

Building a Custom VPN From Scratch (HLD v1)

Designing a userspace VPN using C++, Linux TUN, UDP, and Android VpnService

Shivesh Chaturvedi · 2026-01-03 16:35 · 3 claps · 2.9 min read
#vpn-server #cpp-programming #socket-programming #network-programming #udp-protocol
Open on Medium ↗
Wiki topics: 💻 · Programming 🔒 · Cybersecurity 🔓 · Open Source 🔭 · Astronomy & Space

Building a Custom VPN From Scratch (HLD v1)

Designing a userspace VPN using C++, Linux TUN, UDP, and Android VpnService

Introduction

Most developers use VPNs, but very few ever try to build one from scratch.

This project is an attempt to deeply understand:

  • how VPNs actually move packets,
  • how userspace networking interacts with the Linux kernel,
  • and where performance bottlenecks really come from.

Instead of starting with production-grade security or kernel modules, I focused on correctness, clarity, and learning, and built a minimal end-to-end VPN:

  • Server: C++ on Linux (AWS EC2)
  • Client: Android VpnService (Kotlin)
  • Transport: UDP
  • Tunnel: Linux TUN interface
  • Encryption (temporary): XOR (placeholder)
  • Key exchange: Simple Diffie-Hellman

This article documents the High-Level Design (HLD v1) of the system.

The code will be published on GitHub soon, followed by:

  • HLD v2 (performance-focused)
  • LLD (low-level design & implementation details)

Design Philosophy

Before writing code, I followed one simple mantra:

“Packet flow defines architecture.”

Every box in the HLD exists only to answer one question: What happens to a packet next?

This avoids over-engineering and keeps the system understandable.

System Overview

At a high level, the VPN consists of:

  • An Android client that captures device traffic using a TUN interface
  • A userspace VPN server running on AWS EC2
  • The Linux kernel networking stack, which routes traffic to the internet

The VPN server itself is fully userspace, similar in spirit to OpenVPN.

High-Level Architecture (HLD v1)

Major Components

The architecture can be divided into three clear zones:

1️⃣ Client Side (Android)

  • Uses Android VpnService
  • Creates a userspace TUN interface
  • Captures IP packets from the device
  • Encrypts packets
  • Sends them over UDP to the server

This ensures all device traffic flows through the VPN tunnel.

2️⃣ Server Side — Userspace (C++ VPN Server)

This is the core of the system.

Main Process

  • Single userspace daemon
  • Runs an event-based loop (select / epoll)
  • Handles both network and tunnel I/O

Network Layer

  • UDP Socket Manager Receives encrypted packets from clients and sends responses back.
  • TUN Manager Reads and writes raw IP packets to the Linux TUN interface.

Protocol Layer

  • Defines packet structure
  • Differentiates between: Handshake packets Data packets

Session Management

  • Handshake Session (temporary) Handles Diffie-Hellman key exchange.
  • Client Session Manager Tracks active clients, assigned VPN IPs, and encryption keys.

Crypto Layer

  • Diffie-Hellman key exchange
  • Symmetric key derivation
  • Encryption/decryption (currently XOR as a placeholder)

Security hardening is intentionally postponed to later versions.

3️⃣ Server Side — Kernel Space (Linux)

Once decrypted packets are written to the TUN interface:

  • Linux kernel routing tables take over
  • NAT and iptables forward traffic
  • Packets reach the public internet
  • Responses return via the same path back to the VPN server

This cleanly separates userspace logic from kernel networking.

Packet Flow (End-to-End)

This packet flow defines the entire architecture:

  1. App traffic enters Android TUN
  2. Client encrypts packet
  3. Packet sent via UDP
  4. Server receives packet in event loop
  5. Protocol layer parses packet
  6. Session manager identifies client
  7. Crypto layer decrypts payload
  8. Packet written to server TUN
  9. Linux kernel routes packet to internet
  10. Response flows back the same way

If you understand this flow, you understand the VPN.

Why This Is HLD v1

This design intentionally avoids:

  • Kernel modules
  • Multi-threading complexity
  • Advanced crypto
  • Control planes
  • Observability systems

The goal of HLD v1 is:

  • correctness
  • clarity
  • learning
  • end-to-end functionality

Performance and scalability are explicitly deferred.

Known Limitations (By Design)

  • Userspace ↔ kernel context switches
  • No batching
  • No zero-copy optimizations
  • Simple encryption
  • select/epoll-based I/O

These limitations are not accidents — they define the roadmap.

What’s Coming Next

This project will evolve in stages:

🔜 Code Release

The full server and Android client code will be published on GitHub.

🔜 HLD v2

  • Performance-oriented design
  • epoll-first architecture
  • Reduced packet copies
  • Batching strategies
  • WireGuard-inspired ideas

🔜 LLD

  • Class diagrams
  • Threading model
  • File structure
  • Exact packet formats
  • Implementation trade-offs

Closing Thoughts

Building a VPN from scratch is not about competing with WireGuard or OpenVPN.

It’s about understanding the stack: from mobile OS → userspace → kernel → network → crypto → back again.

This HLD v1 represents a solid, minimal, and correct foundation.

Everything else builds on top of this.

Code and future designs coming soon.


메타데이터
post_id
f8fce3246d70
slug
building-a-custom-vpn-from-scratch-hld-v1-f8fce3246d70
url
https://medium.com/@bvenom87/building-a-custom-vpn-from-scratch-hld-v1-f8fce3246d70
canonical_url
https://medium.com/@bvenom87/building-a-custom-vpn-from-scratch-hld-v1-f8fce3246d70
author_url
https://medium.com/@bvenom87
status
ok
fetched_at
2026-07-13 17:33:19