OVERVIEW SERVER CLIENT MOBILE

SET UP YOUR OWN WIREGUARD VPN

// Reclaim your digital sovereignty.

// WHAT WE'RE BUILDING

In this tutorial, you'll set up your own WireGuard VPN server. WireGuard is a modern, fast, and secure VPN protocol that uses cutting-edge cryptography. Unlike older VPNs that are complex and slow, WireGuard is lightweight - the entire codebase is only about 4,000 lines. This makes it faster, more secure, and easier to audit.

// WHY THIS MATTERS

Every time you connect to public WiFi at a coffee shop, airport, or hotel, you're trusting that network with all your traffic. Anyone on that network can potentially intercept your passwords, emails, and browsing activity. A VPN encrypts all your traffic, making it unreadable to eavesdroppers. But commercial VPNs have a problem - they can see all your traffic too. When you run your own VPN, only you control it. No logs, no data sharing, no subscriptions.

// What You'll Learn

This project teaches you about:

Why WireGuard?

WireGuard was designed to be simpler and faster than existing VPN solutions. Here's why it matters:

Prerequisites

Before starting this tutorial, make sure you've completed:

If you haven't completed these, check out our other tutorials first!

// Understanding VPN Concepts

What is a VPN?

A VPN (Virtual Private Network) creates an encrypted tunnel between your device and a server. All your internet traffic flows through this tunnel, making it invisible to anyone on your local network or your ISP (Internet Service Provider).

When you use a VPN, websites see the VPN server's IP address instead of your real IP address. This provides two key benefits:

How WireGuard Works

WireGuard uses a simple but powerful architecture:

Architecture

Your VPN will work like this:

┌─────────────┐         ┌─────────────┐         ┌─────────────┐
│   Your      │         │   VPS       │         │   Internet  │
│   Device    │────VPN──│   Server    │─────────│   World     │
│             │  Tunnel  │  (WireGuard)│         │             │
└─────────────┘         └─────────────┘         └─────────────┘
        

All your traffic goes from your device → VPN server → internet. The return traffic comes back the same way. To the website you're visiting, the request appears to come from your VPS.

WireGuard vs Other VPNs

Let's compare WireGuard to other popular VPN solutions:

Feature WireGuard OpenVPN Commercial VPN
Speed Very Fast Moderate Varies
Code Size ~4,000 lines ~600,000 lines Proprietary
Security Excellent Good Unknown
Setup Difficulty Easy Hard Very Easy
Privacy You control You control Provider sees all

// Part 1: Set Up Local Development

First, let's set up the project on your local machine. We'll use Docker to run WireGuard locally for testing.

1.1 Create Project Directory

$ mkdir -p ~/projects/wireguard-vpn
# Create project folder
$ cd ~/projects/wireguard-vpn
$ mkdir -p config
# Create config directory for persistent data

1.2 Initialize Git

$ git init
$ git config user.name "Your Name"
$ git config user.email "you@example.com"

1.3 Create .gitignore

$ cat > .gitignore << 'EOF'
# Configuration files with secrets
config/peer*.conf
config/server*.json

# Environment files
.env

# Editor files
.vscode/
.idea/
*.swp

# OS files
.DS_Store
Thumbs.db
EOF

// Part 2: Dockerize Your VPN Server

We'll use linuxserver/wireguard, a well-maintained Docker image that makes WireGuard easy to set up. It handles all the complex key generation for you.

2.1 Create docker-compose.yml

$ cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  wireguard:
    image: linuxserver/wireguard:latest
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - SERVERURL=auto
      - SERVERPORT=51820
      - PEERS=5
      - PEERDNS=auto
      - INTERNAL_SUBNET=10.13.13.0
      - ALLOWEDIPS=0.0.0.0/0
    volumes:
      - ./config:/config
      - /lib/modules:/lib/modules
    ports:
      - "51820:51820/udp"
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped
EOF

Understanding the Configuration

2.2 Run WireGuard Locally

$ docker-compose up -d
# Start the WireGuard container
Creating network "wireguard-vpn_default" with the default driver
Creating wireguard ... done

Give it a few seconds to generate keys, then check the logs:

$ docker-compose logs -f wireguard
# Watch the logs

You'll see the server keys being generated. Once it's ready, check the config folder:

$ ls -la config/
drwxr-xr-x  5 user user  4096 Feb 25 10:00 .
drwxr-xr-x  1 user user  4096 Feb 25 10:00 ..
drownied.srht.site/
peer1/
peer2/
peer3/
peer4/
peer5/
server.conf
wg0.conf

2.3 Understanding the Generated Files

The container generates several important files:

Let's look at the server configuration:

$ cat config/server.conf
[Interface]
Address = 10.13.13.1
PrivateKey = SERVER_PRIVATE_KEY_HERE
ListenPort = 51820

[Peer]
# peer1
PublicKey = PEER_PUBLIC_KEY_HERE
AllowedIPs = 10.13.13.2/32
... (more peers)

2.4 Client Configuration

Each peer folder contains a QR code (for mobile) and a .conf file (for desktop). Let's look at peer1:

$ ls -la config/peer1/
peer1.conf
peer1.png  (QR code for mobile)
peer1-preshared.key
peer1.public.key
peer1.private.key

Here's what a client config looks like:

$ cat config/peer1/peer1.conf
[Interface]
PrivateKey = PEER_PRIVATE_KEY
Address = 10.13.13.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = your-server-ip:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

Client Configuration Explained

2.5 Stop the Container

$ docker-compose down
# Stop the container

Your configuration is saved in the config folder. When you run this on your VPS, the same configuration will persist.

// Part 3: Deploy to Your VPS

Now let's put your VPN on the internet. You'll need a VPS with at least 1GB RAM and a static IP address.

3.1 Connect to Your VPS

$ ssh your-username@your-vps-ip

3.2 Install Docker on Your VPS

your-username@vps:~$ sudo apt update
your-username@vps:~$ sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
your-username@vps:~$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
your-username@vps:~$ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
your-username@vps:~$ sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

3.3 Configure Firewall

WireGuard uses UDP port 51820 by default. Let's open that port:

your-username@vps:~$ sudo ufw allow 22/tcp
# Allow SSH
your-username@vps:~$ sudo ufw allow 51820/udp
# Allow WireGuard
your-username@vps:~$ sudo ufw enable

3.4 Transfer Your Code

On your local machine, commit and push to GitHub:

$ cd ~/projects/wireguard-vpn
$ git add . && git commit -m "Add WireGuard VPN configuration"
$ git remote add origin git@github.com:yourusername/wireguard-vpn.git
$ git push -u origin main

On your VPS, clone the repository:

your-username@vps:~$ cd ~ && git clone git@github.com:yourusername/wireguard-vpn.git wireguard

3.5 Configure Environment

Before running, let's customize the configuration for your VPS. You'll want to set the SERVERURL to your actual IP or domain:

your-username@vps:~$ cd ~/wireguard
your-username@vps:~$ nano docker-compose.yml

Change SERVERURL=auto to your actual domain or IP:

      - SERVERURL=your-domain.com

If you don't have a domain, use your VPS IP address:

      - SERVERURL=your-vps-ip-address

3.6 Start WireGuard

your-username@vps:~$ docker-compose up -d
# Start WireGuard
your-username@vps:~$ docker-compose logs -f wireguard
# Watch the logs to see peer configurations being generated

Wait a moment for the keys to generate, then check the config:

your-username@vps:~$ ls -la config/peer1/

3.7 Get Your Client Configuration

Copy the peer1.conf file to your local machine. You can use SCP:

$ scp your-username@your-vps-ip:~/wireguard/config/peer1/peer1.conf ~/Downloads/wg0.conf
# Copy the config file to your Downloads folder

Important Security Note

Keep your peer configuration files private! They contain the private key that gives access to your VPN. Never share them or commit them to Git.

Make sure the config/peer*.conf entries in your .gitignore are correct before pushing to GitHub.

// Part 4: Connect Your Devices

Now let's connect your devices to your new VPN. WireGuard is available for all major platforms.

4.1 Linux Desktop

Install WireGuard:

$ sudo apt install wireguard
# Debian/Ubuntu
$ sudo pacman -S wireguard-tools
# Arch Linux
$ sudo dnf install wireguard-tools
# Fedora

Copy your configuration file to the WireGuard directory:

$ sudo cp ~/Downloads/wg0.conf /etc/wireguard/wg0.conf
$ sudo chmod 600 /etc/wireguard/wg0.conf
# Secure the private key

Start WireGuard:

$ sudo wg-quick up wg0
# Connect to VPN

Check your connection:

$ sudo wg
interface: wg0
  public key: YOUR_PUBLIC_KEY
  private key: (hidden)
  listening port: 51820

  peer: SERVER_PUBLIC_KEY
    endpoint: your-vps-ip:51820
    allowed ips: 0.0.0.0/0
    latest handshake: 1 minute ago
    transfer: 1.2 KiB received, 1.4 KiB sent

Verify your IP changed:

$ curl ipinfo.io
# Check your IP - should show your VPS location

To disconnect:

$ sudo wg-quick down wg0

4.2 macOS

Install WireGuard from Homebrew:

$ brew install wireguard-tools

Or download the official app from the App Store or wireguard.com.

Import your configuration:

Toggle the switch to connect.

4.3 Windows

Download WireGuard from wireguard.com.

Install and open the application:

4.4 iOS (iPhone/iPad)

Install the WireGuard app from the App Store.

To import your config:

Or use the QR code:

your-username@vps:~$ ls config/peer1/peer1.png
# The QR code is stored here

On your iOS device:

4.5 Android

Install WireGuard from Google Play Store or F-Droid.

Import your configuration the same way as iOS - either by QR code or by importing the .conf file.

4.6 Testing Your VPN

Once connected, verify your IP address changed:

$ curl ipinfo.io
{
  "ip": "your-vps-ip-address",
  "city": "New York",
  "region": "New York",
  "country": "US",
  "org": "AS-EXAMPLE-VPS-PROVIDER"
}

The IP should now show your VPS location instead of your actual location!

4.7 Testing DNS Leak Protection

Let's verify your DNS requests are going through the VPN:

$ curl https://dns.google/resolve?name=example.com
# Test DNS resolution through VPN

Or visit dnsleaktest.com to check for DNS leaks.

// Part 5: Advanced Configuration

5.1 Split Tunneling

By default, we're routing all traffic through the VPN (0.0.0.0/0). This is the most secure option, but you might want to only route specific traffic through the VPN.

Edit your peer configuration to only route specific IPs:

AllowedIPs = 10.13.13.0/24, 192.168.1.0/24

This would only route:

Regular internet traffic would go through your normal connection.

5.2 Kill Switch

WireGuard can automatically disconnect if the VPN connection drops, preventing your real IP from being exposed:

# Add to your client config
[Interface]
...
PostUp = iptables -I OUTPUT ! -o wg0 -j DROP
PostDown = iptables -D OUTPUT ! -o wg0 -j DROP

This drops all traffic that doesn't go through WireGuard when the VPN is active.

5.3 Adding More Peers

Need more than 5 client connections? Edit docker-compose.yml:

      - PEERS=10

Then restart:

your-username@vps:~$ docker-compose down && docker-compose up -d

New peer configurations will be generated in peer6/, peer7/, etc.

5.4 Using a Domain Name

If your VPS IP changes (dynamic IP), use a dynamic DNS service. Many providers offer free dynamic DNS:

Once you have a domain, update your peer's endpoint:

Endpoint = your-domain.ddns.net:51820

5.5 Mobile Data

WireGuard works great over mobile data. The PersistentKeepalive setting (25 seconds) helps maintain the connection through NAT.

For best results on mobile:

// Part 6: Maintenance

6.1 Updating WireGuard

your-username@vps:~$ cd ~/wireguard && docker-compose down
your-username@vps:~$ docker-compose pull
your-username@vps:~$ docker-compose up -d

6.2 Viewing Connection Status

your-username@vps:~$ docker-compose exec wireguard wg
interface: wg0
  public key: SERVER_PUBLIC_KEY
  private key: (hidden)
  listening port: 51820

  peer: PEER1_PUBLIC_KEY
    endpoint: 123.45.67.89:51820
    allowed ips: 10.13.13.2/32
    latest handshake: 15 seconds ago
    transfer: 1.2 MiB received, 3.4 MiB sent

  peer: PEER2_PUBLIC_KEY
    endpoint: 98.76.54.32:51820
    allowed ips: 10.13.13.3/32
    latest handshake: 2 minutes ago
    transfer: 500 KiB received, 1.1 MiB sent

The "latest handshake" shows when each peer last successfully communicated. If it says "0 seconds ago" or very recent, the connection is active.

6.3 Troubleshooting

Can't connect?

Connection drops?

Slow speeds?

6.4 Backup Your Keys

Back up your configuration regularly:

your-username@vps:~$ tar -czf wireguard-backup-$(date +%Y%m%d).tar.gz config/

Store this backup securely. If you lose your keys, you'll need to regenerate them.

// Summary

Congratulations! You've set up your own VPN server!

What You Can Do Now

Next Steps:

You now have complete control over your internet connection. No subscriptions, no logs, no tracking. Just secure, private internet access anywhere in the world.

The revolution will not be proprietary.