GuidesNetwork and VPNYour own WireGuard VPN

Set up your own WireGuard VPN on Debian

A WireGuard VPN on your own Debian server in about 15 minutes. Your phone, laptop or router browses over the server's IPv4 address, and each device gets its own public IPv6 address from the server's /64.

Tested on Debian 13 (trixie) on a Melonslab server Updated September 25, 2026

Recommended server for this guide

VC-S Micro · 2 vCPU · 8 GB Memory · 250 GB Storage

Month to month, no lock-in 7-day money-back guarantee

€7.99/mo

Deploy now
On this page

What you will set up

A WireGuard server that your phone, laptop or router connects to. While connected, a device:

  • browses the internet over IPv4 through your server's address, and
  • gets its own public IPv6 address from the /64 that comes with your server.

Every command below was run on a fresh Melonslab server with Debian 13, and the result checked from a connected device.

Before you start

You need:

  • a server with Debian 13 and root access,
  • an IPv4 address on the server, so devices can reach it from any network, and
  • the WireGuard app on each device (for Android, iOS, Windows, macOS and Linux, from wireguard.com).

The examples use 203.0.113.10 for the server's IPv4 address and 2001:db8:1f::/64 for its IPv6 range. Replace them with your own throughout.

1. Install WireGuard

apt update
apt install -y wireguard nftables qrencode

nftables shares the server's IPv4 address with your devices, and qrencode puts a configuration on your phone's screen as a QR code.

2. Find your interface and IPv6 range

ip route show default
ip -6 addr show scope global

The first command shows your network interface after dev, usually eth0. The second shows your IPv6 address and range, for example 2001:db8:1f::a/64. The range is the part before the last ::, here 2001:db8:1f::/64. The examples use eth0; if yours is different, change it everywhere below.

3. Create keys

Every side of the tunnel has a private key, which never leaves it, and a public key, which you give to the other side.

cd /etc/wireguard
umask 077
wg genkey | tee server.key | wg pubkey > server.pub
wg genkey | tee phone.key | wg pubkey > phone.pub

umask 077 keeps the key files readable by root only.

4. Turn on forwarding

Your server has to pass traffic between the tunnel and the internet:

cat > /etc/sysctl.d/99-wireguard.conf <<EOF
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.eth0.proxy_ndp = 1
EOF
sysctl --system

The last line matters for IPv6. On Melonslab, your /64 is on the network link rather than routed to your server: the router asks on the network which machine has each address. Your server has to answer on behalf of the devices in its tunnel, and proxy_ndp lets it, together with one entry per device that the next step adds. Without it, IPv4 works in the tunnel and IPv6 silently does not.

Your server's own IPv6 route is set statically, so turning on forwarding does not affect it.

5. Configure the server

Create /etc/wireguard/wg0.conf:

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY
# IPv4: devices share the server's address
PostUp = nft add table ip wireguard
PostUp = nft add chain ip wireguard postrouting "{ type nat hook postrouting priority srcnat; }"
PostUp = nft add rule ip wireguard postrouting ip saddr 10.8.0.0/24 oifname eth0 masquerade
PostDown = nft delete table ip wireguard
# IPv6: each device has its own address from your /64
PostUp = ip -6 neigh add proxy 2001:db8:1f::100 dev eth0
PostDown = ip -6 neigh del proxy 2001:db8:1f::100 dev eth0

[Peer]
# phone
PublicKey = PHONE_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32, 2001:db8:1f::100/128

Replace SERVER_PRIVATE_KEY with the output of cat server.key and PHONE_PUBLIC_KEY with the output of cat phone.pub. The phone gets 10.8.0.2 inside the tunnel and 2001:db8:1f::100 as its public IPv6 address.

6. Start WireGuard

systemctl enable --now wg-quick@wg0
wg show

wg show lists the interface and the phone as a peer. WireGuard now also starts on every boot.

7. Connect your first device

Create /etc/wireguard/phone.conf, the configuration the phone will use:

[Interface]
PrivateKey = PHONE_PRIVATE_KEY
Address = 10.8.0.2/32, 2001:db8:1f::100/128
DNS = 1.1.1.1, 2606:4700:4700::1111

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = 203.0.113.10:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

Replace PHONE_PRIVATE_KEY with cat phone.key and SERVER_PUBLIC_KEY with cat server.pub. AllowedIPs = 0.0.0.0/0, ::/0 sends all of the phone's traffic through the tunnel, and DNS sets the resolvers the WireGuard app uses while connected. To answer those lookups on your own server instead, see the Unbound guide.

To load it on the phone, show it as a QR code and scan it with the WireGuard app:

qrencode -t ansiutf8 < phone.conf

On a laptop, import phone.conf into the WireGuard app instead.

8. Check that it works

Connect, then open ifconfig.co in the device's browser. It shows the address the device is using, normally its own IPv6 address, 2001:db8:1f::100.

If the device is a laptop, you can check both:

curl -4 ifconfig.co
curl -6 ifconfig.co

The first should print your server's IPv4 address, 203.0.113.10, and the second the laptop's own IPv6 address.

Adding more devices

Each device needs its own keys and addresses. For a laptop, create keys:

cd /etc/wireguard
umask 077
wg genkey | tee laptop.key | wg pubkey > laptop.pub

Add a peer to the end of wg0.conf, with the next free addresses:

[Peer]
# laptop
PublicKey = LAPTOP_PUBLIC_KEY
AllowedIPs = 10.8.0.3/32, 2001:db8:1f::101/128

Add the laptop's IPv6 address to the [Interface] section, under the phone's lines:

PostUp = ip -6 neigh add proxy 2001:db8:1f::101 dev eth0
PostDown = ip -6 neigh del proxy 2001:db8:1f::101 dev eth0

Then restart WireGuard, which drops connected devices for a moment:

systemctl restart wg-quick@wg0

The laptop's own configuration is the phone's with its private key and addresses swapped in.

Troubleshooting

The device never connects. wg show on the server shows no "latest handshake" for it. Check that the Endpoint is your server's IPv4 address and that UDP port 51820 reaches the server. Debian does not turn on a firewall by default. If you use ufw as in the security guide, add its two WireGuard rules.

IPv4 works, IPv6 does not. Check that forwarding and proxy_ndp are on, and that the device's address has a proxy entry:

sysctl net.ipv6.conf.all.forwarding net.ipv6.conf.eth0.proxy_ndp
ip -6 neigh show proxy

Each device's IPv6 address should be listed. If one is missing, its PostUp line is missing from wg0.conf.

Running a VPN for customers?

These steps are for a VPN you, your household or your team use. A VPN, proxy or exit service offered to customers needs capacity planned and priced for it, so talk to our sales team before you start.

Run it on your own server

VC-S Micro

€7.99/mo

vCPU
2
Memory
8 GB
Storage
250 GB
Transfer
10 TB
Standard
HDD · RAID 10
  • Full root access
  • Native /64 IPv6
  • RAID-protected storage
  • Malmö, Sweden
  • Month to month, no lock-in
  • 7-day money-back guarantee
All guides