Building a Custom VPN From Scratch (HLD v1)
Designing a userspace VPN using C++, Linux TUN, UDP, and Android VpnService
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:
- App traffic enters Android TUN
- Client encrypts packet
- Packet sent via UDP
- Server receives packet in event loop
- Protocol layer parses packet
- Session manager identifies client
- Crypto layer decrypts payload
- Packet written to server TUN
- Linux kernel routes packet to internet
- 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