To run your own WireGuard VPN on a VPS, install the wireguard package, create a key pair for the server and for every device, and write /etc/wireguard/wg0.conf with a private address range and UDP port 51820. Then turn on IP forwarding and NAT, open the port and start wg-quick@wg0. Each laptop or phone becomes a [Peer] with its own key and tunnel address. On Debian 12 or 13 and Ubuntu 22.04 or 24.04, the whole setup takes about fifteen minutes.
Not sure yet whether you need your own VPN server or a VPN subscription? VPS vs VPN sets out what each one does.
apt update && apt install -y wireguard iptables qrencode
cd /etc/wireguard && umask 077
wg genkey | tee server.key | wg pubkey > server.pub
# write /etc/wireguard/wg0.conf (below), then:
echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-wireguard.conf
sysctl --system
ufw allow 51820/udp # if ufw is active, plus:
ufw route allow in on wg0 out on eth0 # eth0 = your internet-facing interface
systemctl enable --now wg-quick@wg0
wg showThe rest of this guide goes through those steps one at a time, adds the clients, and covers what to check when the tunnel connects but nothing loads.
What do you need?
- A KVM VPS. WireGuard has been part of the mainline Linux kernel since 5.6, so the stock kernels of Debian 12 and 13 and Ubuntu 22.04 and 24.04 include it. Container-based VPS types (OpenVZ, LXC) share the host’s kernel and usually cannot load the module. The difference is explained in KVM vs OpenVZ.
- Root access and a public IP. Clients connect to the server’s public address on one UDP port.
- Very little hardware. WireGuard uses almost no CPU or RAM for a handful of devices. The port speed is what limits you: the VPN can never be faster than the server’s uplink.
- A location that suits you. Websites see the server’s IP, so the VPS location becomes the location you appear to browse from.
Check that the kernel module loads before going further:
sudo modprobe wireguard && echo "wireguard module OK"
systemd-detect-virt # kvm is good; openvz or lxc will likely not workHow do I install WireGuard?
Debian 12 and 13, Ubuntu 22.04 and 24.04
sudo apt update
sudo apt install -y wireguard iptables qrencodewireguard pulls in wg and wg-quick. iptables is listed because the NAT rules below use it and minimal Debian and Ubuntu images do not always include it. qrencode turns a client config into a QR code for phones.
Rocky, AlmaLinux and Alpine
# Rocky Linux 9, AlmaLinux 9
sudo dnf install -y wireguard-tools
# Alpine
apk add wireguard-toolsKey generation and the config files below are the same everywhere. The forwarding, firewall and service steps are written for Debian and Ubuntu. Rocky and Alma use firewalld instead of ufw, and Alpine uses OpenRC instead of systemd, so adapt those parts.
How do I set up the server?
Every command in this section runs as root. Start a root shell with sudo -i.
- 1Generate the server keys
keys cd /etc/wireguard umask 077 # new files readable by root only wg genkey | tee server.key | wg pubkey > server.pub cat server.key # you paste this into wg0.conf cat server.pub # clients need this oneThe private key never leaves the server. The public key goes into every client config.
- 2Find the interface that faces the internet
egress interface ip route show default # default via 203.0.113.1 dev eth0 proto staticThe name after
devis what you need:eth0in this example, oftenens3,ens18orenp1s0on VPS images. Replaceeth0in the config below if yours differs. - 3Write /etc/wireguard/wg0.conf
/etc/wireguard/wg0.conf [Interface] Address = 10.8.0.1/24 ListenPort = 51820 PrivateKey = <contents of server.key> PostUp = iptables -I FORWARD -i %i -j ACCEPT; iptables -I FORWARD -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE10.8.0.0/24is the private range inside the tunnel. The server is10.8.0.1, and clients get.2,.3and so on. Pick another private range if 10.8.0.0/24 is already used on a network you connect from.wg-quickreplaces%iwith the interface name. The threePostUprules let tunnel traffic through the server, let the replies back in, and rewrite the source address to the server’s public IP (NAT).PostDownremoves them again. - 4Turn on IP forwarding
forwarding echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-wireguard.conf sysctl --system sysctl net.ipv4.ip_forward # must print 1Without forwarding, clients connect and complete the handshake, but no traffic leaves the server. This is the most common reason for “connected, but no internet”.
- 5Open the firewall
ufw ufw allow OpenSSH # before anything else, if ufw is new ufw allow 51820/udp ufw route allow in on wg0 out on eth0 ufw status verboseAllowing SSH first keeps you from locking yourself out when ufw is enabled for the first time.
51820/udpis WireGuard’s port. Therouterule is needed because ufw drops forwarded traffic by default (DEFAULT_FORWARD_POLICY="DROP"in/etc/default/ufw). If ufw is not active and you run no other firewall, nothing is needed here. Also check for a firewall in your provider’s panel. For ufw basics, see our ufw firewall setup. - 6Start the tunnel
start systemctl enable --now wg-quick@wg0 wg showwg showshould list interfacewg0, its public key andlistening port: 51820.enablebrings the tunnel back after every reboot.
How do I add a laptop and a phone?
Each device needs its own key pair and its own tunnel address. Generating the keys on the server is the quickest way, especially for phones. Delete the client private keys from the server once the devices have them. The WireGuard apps can also create a key pair on the device and show you its public key.
umask 077
wg genkey | tee laptop.key | wg pubkey > laptop.pub
wg genkey | tee phone.key | wg pubkey > phone.pubAdd both devices to the server and apply the change without dropping the tunnel:
cat >> /etc/wireguard/wg0.conf <<EOF
[Peer]
# laptop
PublicKey = $(cat laptop.pub)
AllowedIPs = 10.8.0.2/32
[Peer]
# phone
PublicKey = $(cat phone.pub)
AllowedIPs = 10.8.0.3/32
EOF
wg syncconf wg0 <(wg-quick strip wg0)On the server, AllowedIPs says which tunnel address belongs to which key: one /32 per device. Then write one config file per device:
[Interface]
PrivateKey = <contents of laptop.key>
Address = 10.8.0.2/32
DNS = 9.9.9.9
[Peer]
PublicKey = <contents of server.pub>
Endpoint = 203.0.113.10:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25Endpointis your server’s public IP (or a hostname pointing at it) and the port.AllowedIPs = 0.0.0.0/0, ::/0on the client is a full tunnel: all traffic goes through the VPN. Use10.8.0.0/24instead if you only want to reach the server and other peers.DNSis the resolver the device uses while connected. Any public resolver you trust works.PersistentKeepalive = 25keeps the connection alive through home routers and mobile networks that forget idle UDP flows.
Write phone.conf next to it on the server, with the phone’s private key and Address = 10.8.0.3/32. Show it as a QR code and scan it in the WireGuard app (“add tunnel”, then “scan from QR code”):
qrencode -t ansiutf8 < phone.confCopy laptop.conf to the laptop, for example with scp. On Windows and macOS, import it in the official WireGuard app. On a Linux laptop, save it as /etc/wireguard/wg0.conf and run sudo wg-quick up wg0. When both devices are connected, remove the client secrets from the server:
rm /etc/wireguard/laptop.key /etc/wireguard/phone.key \
/etc/wireguard/laptop.conf /etc/wireguard/phone.confShould I tunnel IPv6 as well?
Most VPS plans come with both an IPv4 and an IPv6 address. With the configs above, the client sends its IPv6 traffic into the tunnel (that is what ::/0 does), but the server only forwards IPv4, so that traffic is dropped instead of leaking past the VPN. Websites fall back to IPv4. For most personal VPNs that is the right trade-off.
If you do want IPv6 through the tunnel, give the tunnel an IPv6 range and NAT it the same way:
# server [Interface]
Address = 10.8.0.1/24, fd42:42:42::1/64
# append to PostUp (and the matching -D versions to PostDown):
# ip6tables -I FORWARD -i %i -j ACCEPT; ip6tables -I FORWARD -o %i -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; ip6tables -t nat -A POSTROUTING -s fd42:42:42::/64 -o eth0 -j MASQUERADE
# server [Peer] for the laptop
AllowedIPs = 10.8.0.2/32, fd42:42:42::2/128
# laptop [Interface]
Address = 10.8.0.2/32, fd42:42:42::2/128
# /etc/sysctl.d/99-wireguard.conf
net.ipv6.conf.all.forwarding = 1How do I check that the VPN works?
wg show
# peer: <laptop public key>
# endpoint: 198.51.100.7:53211
# allowed ips: 10.8.0.2/32
# latest handshake: 14 seconds ago
# transfer: 1.20 MiB received, 8.43 MiB sentA recent latest handshake and growing transfer counters mean the tunnel is up. On the client, check which address the internet sees. It should be the server’s IP, not your own:
ping -c 3 10.8.0.1 # the server through the tunnel
curl -4 https://icanhazip.com # should print the VPS's public IPv4A what is my IP page in the browser does the same job, and shows whether you came in over IPv4 or IPv6. To check that DNS queries also go through the tunnel, run a DNS leak test while connected: it should show only the resolver you set in DNS =.
Why is WireGuard not working?
No handshake at all
- UDP 51820 is blocked by ufw, a provider firewall, or the network you connect from. Some public Wi-Fi blocks unusual UDP ports. On the server,
tcpdump -ni eth0 udp port 51820(from thetcpdumppackage) shows whether packets arrive at all. - Wrong Endpoint, such as a typo in the IP or a port that does not match
ListenPort. - Swapped keys. The client’s
[Peer]needs the server’s public key. The server’s[Peer]needs the client’s public key. A private key in aPublicKeyline fails without an error message. - The service is not running. Run
systemctl status wg-quick@wg0. A typo inwg0.confstops it at start.
Handshake, but no internet
sysctl net.ipv4.ip_forwardprints0: repeat step 4.- The NAT rule names the wrong interface. Compare
iptables -t nat -S POSTROUTINGwithip route show default. - ufw is active without the
ufw route allowrule, or Docker on the same server has set theFORWARDpolicy toDROP. The-I FORWARDrules inPostUpare there for that case. Check them withiptables -S FORWARD.
Pages do not load by name, or DNS leaks
- On a Linux client,
wg-quickapplies theDNS =line throughresolvconf. If it stops withresolvconf: command not foundon a machine that runssystemd-resolved(the Ubuntu default), link its compatibility mode into place withsudo ln -s /usr/bin/resolvectl /usr/local/bin/resolvconf. Without systemd-resolved, installopenresolvinstead. - Browsers with their own DNS-over-HTTPS setting bypass the tunnel’s resolver. Turn it off or point it at the same resolver.
Some sites hang or large downloads stall
That points to an MTU problem on the path. Add MTU = 1380 to the client’s [Interface] section and reconnect. WireGuard’s default is 1420.
What does your own VPN hide, and what not?
A VPN on your own server encrypts everything between your device and the server. The café Wi-Fi, the hotel network and your ISP see only encrypted UDP to one address. Websites see the server’s IP instead of yours.
It does not make you anonymous. From the server onward, your traffic travels as ordinary internet traffic: the hosting provider’s network sees the destinations your ISP used to see, plus anything not protected by HTTPS. The IP is rented in your name and used by nobody else, so everything that comes from it points back to one customer. Some services also treat datacenter IPs differently from home connections. Our guide to anonymous VPS hosting covers what can and cannot be hidden.
Which server should you use?
For a personal VPN, the smallest plan is enough. The entry Standard KVM plan has 2 cores, 4 GB of RAM and a 200 Mbit/s port, from 4.99 EUR a month in Amsterdam. Choose the next plan up, with a 1 Gbit/s port, if the tunnel should keep up with a fast home connection. An Amsterdam VPS gives you a Dutch exit IP inside the EU.
Once the tunnel works, lock down the rest of the server with SSH hardening. If you want to reach a Windows server’s Remote Desktop through this tunnel instead of over the open internet, see RDP through your own WireGuard server and securing a Windows RDP server.
Frequently asked
Is WireGuard faster than OpenVPN?
Usually, yes. WireGuard runs inside the Linux kernel, uses a small fixed set of modern ciphers and has less protocol overhead, so it tends to reach higher throughput with less CPU on the same server. Real numbers depend on the CPU, the network path and the MTU, so measure on your own setup.
How many devices can connect to my WireGuard server?
WireGuard has no fixed limit. Every device needs its own key pair and its own tunnel address as a [Peer] on the server; a /24 range such as 10.8.0.0/24 leaves room for 253 clients. On a small VPS the port speed limits you long before the number of peers does.
Does a VPN on my own VPS make me anonymous?
No. It hides your traffic from the local network and your ISP and shows websites the server's IP instead of yours, but that IP is rented in your name and used only by you, and the hosting provider's network sees the traffic that leaves the server. It is a privacy tool for untrusted networks, not an anonymity tool.
Which port does WireGuard use?
UDP only, 51820 by convention. Any free UDP port works as long as ListenPort on the server and the Endpoint port on every client match; WireGuard never uses TCP, so the port must be opened for UDP in every firewall on the way.