🛠️ Tutorials · ⏱ 9 min read

Build Your Own WireGuard VPN on a VPS in 2026: The Complete Guide

2026 tutorial on self-hosting a WireGuard VPN on a Linux VPS. Covers installation, key generation, server and client configuration (mobile, PC), routing, NAT, kill switch, and DNS. Includes exact commands and ready-to-use configs.

S By Selfhostr Team · independent tests
Build Your Own WireGuard VPN on a VPS in 2026: The Complete Guide
ⓘ This article may contain affiliate links (no extra cost to you, it supports our tests). See the disclosure.
💰
€4/month
Cost
⏱️
20-30 min
Install Time
🌐
UDP 51820
Protocol
📝
Few thousand lines
Code Size

👍 What we like

  • Lightweight with minimal code compared to OpenVPN
  • Integrated directly into the Linux kernel
  • Significantly faster performance
  • No third-party trust required for data privacy

👎 What to watch

  • Requires manual configuration of routing and NAT
  • Needs VPS hardening for optimal security
  • Must ensure UDP port 51820 is not blocked
📑 Contents

Commercial VPNs are convenient, but you pay a subscription to trust a third party with your data. Setting up your own WireGuard VPN on a VPS changes the game: you get a fixed IP you control, a modern encrypted tunnel, and the certainty that no connection logs are being sold, since you are the operator. It is ideal for securing your traffic on public Wi-Fi, accessing your homelab remotely, or simply having a clean Internet exit.

WireGuard has established itself as the standard in 2026: it consists of just a few thousand lines of code (compared to hundreds of thousands for OpenVPN), it is integrated into the Linux kernel, and it is significantly faster. In this guide, we install WireGuard on a VPS, generate server and client keys, configure routing and NAT to route all traffic, and connect a phone (via QR code) and a computer. By the end, you will have a functional and secure personal VPN.

Prerequisites

WireGuard operates over UDP on port 51820 by default. Ensure your host does not block incoming UDP (rare, but worth checking).

Step 1: Install WireGuard

On Ubuntu/Debian, WireGuard is in the standard repositories:


sudo apt update

sudo apt install -y wireguard wireguard-tools

The kernel module has been included in Linux since version 5.6, so there is nothing else to compile. Verify the tools are available:


wg --version

Step 2: Enable IP routing on the server

For the VPS to route your clients’ traffic to the Internet, enable IP forwarding. Edit the sysctl configuration:


sudo nano /etc/sysctl.d/99-wireguard.conf

Add:


net.ipv4.ip_forward = 1

net.ipv6.conf.all.forwarding = 1

Apply without rebooting:


sudo sysctl --system

Verify:


sysctl net.ipv4.ip_forward

The output should display net.ipv4.ip_forward = 1.

Step 3: Generate server keys

WireGuard uses public/private key cryptography. Generate the server key pair in a protected directory:


sudo mkdir -p /etc/wireguard

sudo chmod 700 /etc/wireguard

cd /etc/wireguard

umask 077

wg genkey | sudo tee server_private.key | wg pubkey | sudo tee server_public.key

The umask 077 command ensures that key files are readable only by root. Display both keys; you will need them:


echo "SERVER PRIVATE KEY: $(sudo cat /etc/wireguard/server_private.key)"

echo "SERVER PUBLIC KEY: $(sudo cat /etc/wireguard/server_public.key)"

Step 4: Identify the outgoing network interface

NAT needs to know which interface goes out to the Internet. Find it:


ip route get 1.1.1.1 | grep -oP 'dev \K\S+'

Note the returned name (often eth0, ens3, or enp1s0). We will use it in the config. In the following steps, we assume eth0; replace it with your own.

Step 5: Create the server configuration

Create the wg0 interface file:


sudo nano /etc/wireguard/wg0.conf

Paste the following configuration, replacing SERVER_PRIVATE_KEY with the server’s private key and eth0 with your outgoing interface:


[Interface]

# Server address in the private VPN network

Address = 10.8.0.1/24

ListenPort = 51820

PrivateKey = SERVER_PRIVATE_KEY



# Enable NAT so clients can access the Internet via the VPS

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

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



# Client [Peer] blocks will be added below

We have chosen the private subnet 10.8.0.0/24 for the VPN. The server is 10.8.0.1, and clients will take 10.8.0.2, 10.8.0.3, etc.

Secure the file:


sudo chmod 600 /etc/wireguard/wg0.conf

Step 6: Open the port in the firewall

If you use UFW (recommended), allow the WireGuard port:


sudo ufw allow 51820/udp

sudo ufw reload

Verify that the rule is present:


sudo ufw status | grep 51820

Step 7: Start the WireGuard server

WireGuard integrates with systemd via wg-quick. Enable and start the interface:


sudo systemctl enable --now wg-quick@wg0

Verify that the interface is up:


sudo wg show

You should see the wg0 interface with its public key and listening port. No peers yet, which is normal.

Step 8: Configure a first client (smartphone)

Generate a key pair for the client (each client has its own). Still on the server, in /etc/wireguard:


cd /etc/wireguard

umask 077

wg genkey | sudo tee client_phone_private.key | wg pubkey | sudo tee client_phone_public.key

Declare the client on the server

Add a [Peer] block to the end of /etc/wireguard/wg0.conf:


sudo nano /etc/wireguard/wg0.conf

[Peer]

# Phone

PublicKey = CLIENT_PHONE_PUBLIC_KEY

AllowedIPs = 10.8.0.2/32

AllowedIPs = 10.8.0.2/32 tells the server that this peer is reachable at address 10.8.0.2. Reload the configuration without dropping existing connections:


sudo systemctl restart wg-quick@wg0

Create the client config file

On the server, prepare the client config content. First, retrieve the necessary values:


echo "CLIENT PRIVATE KEY: $(sudo cat /etc/wireguard/client_phone_private.key)"

echo "SERVER PUBLIC KEY: $(sudo cat /etc/wireguard/server_public.key)"

The client configuration looks like this (adapt as needed):


[Interface]

PrivateKey = CLIENT_PHONE_PRIVATE_KEY

Address = 10.8.0.2/32

DNS = 1.1.1.1



[Peer]

PublicKey = SERVER_PUBLIC_KEY

Endpoint = 203.0.113.10:51820

# All traffic goes through the VPN ("full tunnel")

AllowedIPs = 0.0.0.0/0, ::/0

PersistentKeepalive = 25

Replace 203.0.113.10 with your VPS’s public IP. The AllowedIPs = 0.0.0.0/0 on the client side means “route all traffic through the tunnel,” which makes this a full VPN. PersistentKeepalive = 25 keeps the tunnel open behind NATs, which is useful for mobility.

Generate a QR code for the phone

The easiest way to configure a mobile device is to display the config as a QR code to scan with the WireGuard app. Install the tool and generate the code (paste the client config into a temporary file first):


sudo apt install -y qrencode

# Create the client file then:

qrencode -t ansiutf8 < /tmp/client_phone.conf

Open the WireGuard app on your phone, choose “Add tunnel > Scan QR code,” scan, and activate the tunnel. Immediately delete the temporary file containing the private key:


shred -u /tmp/client_phone.conf

Step 9: Connect a computer (Linux / Windows / macOS)

For a computer, proceed similarly: a dedicated key pair, a [Peer] block on the server with AllowedIPs = 10.8.0.3/32, and a .conf file on the client identical to the phone’s (changing the private key and the 10.8.0.3/32 address).

On Linux, place the config in /etc/wireguard/wg0.conf and run:


sudo wg-quick up wg0

On Windows and macOS, install the official WireGuard application, import the .conf file, and activate the tunnel with one click.

Verification

Once the tunnel is active on a client, check on the server that the handshake has occurred:


sudo wg show

You should see a recent latest handshake line under the peer and rising transfer counters. On the client side, check your public IP: it should now be that of your VPS.


curl -s https://api.ipify.org && echo

Also test that DNS is not leaking (DNS queries must pass through the server configured in DNS =). Visit a DNS leak test site from the connected client.

Best practices and security

  • One key per device. Never share the same key pair between multiple clients: if a device is lost, you revoke only its peer without affecting others.

  • Revoking a client is done by removing its [Peer] block from wg0.conf and then restarting the service. The key becomes useless instantly.

  • Split tunnel. If you only want to route access to your homelab (and not all your traffic), replace AllowedIPs = 0.0.0.0/0 on the client side with the relevant subnet, e.g., 10.8.0.0/24, 192.168.1.0/24.

  • Kill switch. The WireGuard mobile app offers a “Block traffic when VPN is off” option. On desktop, wg-quick can add firewall rules to prevent any leaks if the tunnel drops.

  • Private DNS. To avoid relying on any public resolver, host an AdGuard Home or Pi-hole on the VPS and point DNS = 10.8.0.1 on the client side.

  • Backup /etc/wireguard. This folder contains all your keys; include it in your backup strategy (see encrypted backups with restic).

FAQ

Is WireGuard really faster than OpenVPN?

Yes, significantly. Thanks to its kernel integration and minimalist codebase, WireGuard offers higher throughput and lower latency than OpenVPN, especially on mobile where connection establishment is almost instantaneous. The trade-off: fewer esoteric configuration options, but for 99% of use cases, this is an advantage. See WireGuard vs OpenVPN vs Tailscale.

Is my own VPN more anonymous than a commercial VPN?

Different, not necessarily more anonymous. You have the guarantee that no logs are sold, and total control. But the exit IP is unique and associated with you (rented in your name at the host), so it is not suitable for mass anonymity. It is excellent for traffic privacy, remote access, and bypassing insecure Wi-Fi. For strong anonymity, a multi-user no-log VPN remains relevant: see our best VPN comparison.

What if the connection does not establish (no handshake)?

Check in order: port 51820/udp is open (sudo ufw status), the client-side Endpoint points to the correct public IP, IP forwarding is active (sysctl net.ipv4.ip_forward), and the client’s public key declared on the server matches. A sudo wg show without a handshake almost always indicates a network block or a key/endpoint error.

How many clients can I connect?

Dozens without problem on a small VPS: WireGuard is extremely lightweight in CPU and RAM. The practical limit is rather your VPS’s bandwidth and the monthly traffic quota of your plan. Each client just needs its [Peer] block and a unique address in the 10.8.0.0/24 subnet.

Can I access my home local network via this VPN?

Yes, this is a classic use case. If your homelab is on the same VPS or accessible from it, add the relevant subnet to the client’s AllowedIPs. To reach a network behind another machine, you need to configure that machine as a relay peer with appropriate routing.

You now have an encrypted, fast, and fully controlled personal VPN. Add your devices over time and remember to back up your keys. To stay updated on self-hosting news and VPS deals, join our Telegram monitoring bot.

Tags: VPNWireGuardVPSLinuxSelf-hostingTutorialNetwork SecurityPrivacy

Related

🛠️ Tutorials

Self-Hosting Your Website in 2026: Complete Guide (VPS, Docker, HTTPS)

2026 technical guide to self-hosting on a VPS: choosing plans, Docker setup, Let's Encrypt HTTPS, security, and real costs. Compare self-hosting vs. cloud.

Read
🛠️ Tutorials

Install and Secure an Ubuntu 24.04 VPS in 2026: The Complete A to Z Guide

Master your server with this 2026 guide to installing and hardening an Ubuntu 24.04 VPS. Covers SSH keys, root disablement, UFW, fail2ban, auto-updates, and essential security best practices with ready-to-copy commands.

Read
🛠️ Tutorials

Nextcloud All-in-One Docker Tutorial 2026: Full Setup & Auto HTTPS

2026 guide to deploying Nextcloud All-in-One with Docker. Covers master container, HTTPS reverse proxy, backups, hardening, and troubleshooting. Includes ready-to-use docker-compose and Caddy configs for your personal cloud.

Read