Privacy Tools Guide

Most WireGuard guides only cover IPv4. This leaves an IPv6 leak problem: if your client has native IPv6 connectivity but your VPN tunnel only handles IPv4, traffic to IPv6 addresses bypasses the tunnel entirely and exposes your real IP. This guide sets up WireGuard with both IPv4 and IPv6 routing to prevent leaks.

Prerequisites

Step 1: Enable IPv6 on the VPS

Check if your VPS has an IPv6 address:

ip -6 addr show
# Look for a global address (not just link-local fe80::)

Enable IPv6 forwarding:

sudo tee -a /etc/sysctl.conf > /dev/null <<'EOF'
# WireGuard IPv4 forwarding
net.ipv4.ip_forward = 1

# WireGuard IPv6 forwarding
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding = 1
EOF

sudo sysctl -p

Step 2: Choose Addressing Scheme

For the WireGuard tunnel network:

The ULA range (fd00::/8) is analogous to RFC1918 for IPv6. Use it for WireGuard tunnel addresses.

Step 3: Generate Keys

# Install WireGuard
sudo apt install wireguard

# Server keys
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
chmod 600 /etc/wireguard/server_private.key

# Client keys (run on client or generate on server and distribute securely)
wg genkey | tee /etc/wireguard/client1_private.key | wg pubkey > /etc/wireguard/client1_public.key

cat /etc/wireguard/server_public.key
cat /etc/wireguard/client1_public.key

Step 4: Server Configuration

Create /etc/wireguard/wg0.conf on the server:

[Interface]
# Server Nebula IPv4 and IPv6 addresses
Address = 10.100.0.1/24, fd42:dead:beef::1/64

# Listen port
ListenPort = 51820

# Server private key
PrivateKey = SERVER_PRIVATE_KEY_HERE

# NAT rules for IPv4 (replace eth0 with your public interface name)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; \
         iptables -A FORWARD -o %i -j ACCEPT; \
         iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# IPv6 NAT (using ip6tables)
# If your VPS has a single global IPv6, use NAT
PostUp = ip6tables -A FORWARD -i %i -j ACCEPT; \
         ip6tables -A FORWARD -o %i -j ACCEPT; \
         ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

PostDown = iptables -D FORWARD -i %i -j ACCEPT; \
           iptables -D FORWARD -o %i -j ACCEPT; \
           iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
PostDown = ip6tables -D FORWARD -i %i -j ACCEPT; \
           ip6tables -D FORWARD -o %i -j ACCEPT; \
           ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# Client 1
PublicKey = CLIENT1_PUBLIC_KEY_HERE
AllowedIPs = 10.100.0.2/32, fd42:dead:beef::2/128

Note: If your VPS has a full /64 IPv6 prefix (not just a single address), you can route client IPv6 addresses directly without NAT. Replace the ip6tables MASQUERADE rules with:

PostUp = ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -A FORWARD -o %i -j ACCEPT

And configure each client with a unique address from your delegated prefix.

Step 5: Enable IPv6 NAT Support in the Kernel

IPv6 NAT (MASQUERADE) requires a kernel module:

sudo modprobe ip6table_nat
sudo modprobe ip6_tables

# Make it persistent
echo "ip6table_nat" | sudo tee -a /etc/modules-load.d/ip6tables.conf
echo "ip6_tables" | sudo tee -a /etc/modules-load.d/ip6tables.conf

Start WireGuard:

sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0

Step 6: Client Configuration

Create /etc/wireguard/wg0.conf on the client (Linux) or use the WireGuard app (iOS/Android/Windows):

[Interface]
# Client's tunnel addresses
Address = 10.100.0.2/32, fd42:dead:beef::2/128

# Client private key
PrivateKey = CLIENT1_PRIVATE_KEY_HERE

# Route ALL traffic (both IPv4 and IPv6) through the tunnel
DNS = 10.100.0.1, fd42:dead:beef::1

[Peer]
PublicKey = SERVER_PUBLIC_KEY_HERE
Endpoint = YOUR_VPS_IP:51820

# Route all IPv4 and IPv6 through tunnel
AllowedIPs = 0.0.0.0/0, ::/0

PersistentKeepalive = 25

The key setting is AllowedIPs = 0.0.0.0/0, ::/0 — this routes all IPv4 AND IPv6 traffic through the tunnel, preventing IPv6 leaks.

Bring the interface up:

sudo wg-quick up wg0

Step 7: Run a DNS Server for IPv6 (Optional)

If you want to serve DNS over IPv6 from your WireGuard server, use Unbound:

sudo apt install unbound

sudo tee /etc/unbound/unbound.conf.d/wireguard.conf > /dev/null <<'EOF'
server:
    # Listen on WireGuard interface
    interface: 10.100.0.1
    interface: fd42:dead:beef::1

    # Allow queries from tunnel
    access-control: 10.100.0.0/24 allow
    access-control: fd42:dead:beef::/64 allow

    # Block local queries except from tunnel
    access-control: 0.0.0.0/0 refuse
    access-control: ::/0 refuse

    # Enable IPv6
    do-ip6: yes
    prefer-ip6: no

    # DNSSEC
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
EOF

sudo systemctl enable --now unbound

Step 8: Verify No IPv6 Leaks

# On the client, check your public IPs
curl -4 https://ifconfig.me   # Should show your VPS IPv4
curl -6 https://ifconfig.me   # Should show your VPS IPv6 (not your ISP's IPv6)

# Check all routes
ip -6 route show
# Should show: default dev wg0 (or via the tunnel)

# DNS leak test
drill @fd42:dead:beef::1 google.com
# Should resolve without hitting your ISP's DNS

If curl -6 https://ifconfig.me returns your home IPv6, the tunnel is not capturing IPv6 traffic. Check:

  1. That AllowedIPs includes ::/0
  2. That ip6tables NAT is loaded on the server
  3. That your client OS is not routing IPv6 outside the tunnel