Step by step guide to build a fast, secure WireGuard VPN on your own private server
1. Prerequisites
- A private server (VPS or physical) with a public IPv4 address (example: Ubuntu 22.04 / Debian 12).
- Root or sudo access to the server.
- Basic terminal skills (SSH, editing files with nano / vim).
- A client device (Linux, Windows, macOS, iOS, Android).
Why a private server? You control logs, privacy, and routing. A VPS from a trusted provider (or a home server with proper NAT) works fine.
2. Server setup
Run these commands with sudo on the server.
# update & install WireGuard
sudo apt update && sudo apt install -y wireguard qrencode
qrencode is optional but useful for scanning client configs into mobile apps.
On CentOS/RHEL/Fedora use dnf / yum and the EPEL repository or the distro’s WireGuard package.
3. Generate server and client keys
On the server, create a folder to store keys and protect it:
sudo mkdir -p /etc/wireguard/keys
sudo chmod 700 /etc/wireguard/keys
cd /etc/wireguard/keys
# server keys
sudo wg genkey | sudo tee server_private.key | sudo wg pubkey > server_public.key
# client keys (you can also generate on the client device)
sudo wg genkey | sudo tee client1_private.key | sudo wg pubkey > client1_public.key
# view files (only as root)
sudo ls -l
Important: Keep private keys secret. Use chmod 600 on private key files.
5. Server configuration
Create /etc/wireguard/wg0.conf and paste the configuration below, adjusting addresses and keys.
[Interface]
Address = 10.13.13.1/24 # VPN subnet for server
ListenPort = 51820 # UDP port to listen on
PrivateKey = <SERVER_PRIVATE_KEY>
# Optional: persist tun across reboots
SaveConfig = true
# NAT rules (if using iptables directly — we'll also show systemd hooks below)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -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
# Each client is added as a peer block
[Peer]
PublicKey = <CLIENT1_PUBLIC_KEY>
AllowedIPs = 10.13.13.2/32
# Optional: PersistentKeepalive = 25
Replace <SERVER_PRIVATE_KEY> and <CLIENT1_PUBLIC_KEY> with the contents of the files created earlier (no trailing spaces/newlines when pasting inside the file). Replace eth0 with your public interface name (ip route get 8.8.8.8 helps find it).
You can generate client public and private key using below
wg genkey | tee client_private.key | wg pubkey > client1_public.key
6. Enable IP forwarding
Enable forwarding in sysctl:
sudo sysctl -w net.ipv4.ip_forward=1
# make it permanent
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-sysctl.conf
sudo sysctl --system
7. Set Firewall rules ( If You are Using UFW Firewall )
sudo ufw allow 51820/udp
# edit /etc/default/ufw and set DEFAULT_FORWARD_POLICY="ACCEPT"
# then add these in /etc/ufw/before.rules (above the *filter line) to enable NAT:
# see UFW docs — example NAT rules:
# *nat
# :POSTROUTING ACCEPT [0:0]
# -A POSTROUTING -s 10.13.13.0/24 -o eth0 -j MASQUERADE
# COMMIT
sudo ufw reload
8. Create Client configuration
Create a client config file (example client1.conf):
[Interface]
PrivateKey = <CLIENT1_PRIVATE_KEY>
Address = 10.13.13.2/32
DNS = 1.1.1.1,8.8.8.8
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = your.server.ip.address:51820
AllowedIPs = 0.0.0.0/0, ::/0 # route all traffic through VPN
PersistentKeepalive = 25
- On Linux, sudo wg-quick up ./client1.conf will start the client.
- On Windows, use the official WireGuard app and import the
.conffile. - On iOS/Android, open the WireGuard app, create a new tunnel and either paste the text or scan a QR code.
Generate a QR code for mobile from the server (if qrencode installed):
sudo cat /etc/wireguard/client1.conf | qrencode -t ansiutf8
# or write to PNG
sudo cat /etc/wireguard/client1.conf | qrencode -o client1.png
9. Start, enable and test the VPN
On the Server
sudo systemctl enable --now wg-quick@wg0
sudo wg show # shows peers, transfer, handshake
On the client: bring the tunnel up and check IP routing.
# on Linux client
sudo wg-quick up client1.conf
ip a show dev wg0
curl https://ifconfig.co # should return your server public IP
You can also use WireGuard for Windows, which allows importing .conf files directly and managing connections through its graphical interface. After import, simply toggle the connection to ON to connect.
Download from here
https://www.wireguard.com/install
If curl https://ifconfig.co shows your server’s public IP, traffic is routing through the VPN.
10. Advanced tips
- Multiple clients: add a
[Peer]block per client on the server, incrementing AllowedIPs (e.g., 10.13.13.3/32, 10.13.13.4/32). - Split tunneling: on the client set AllowedIPs to only specific networks (e.g., 192.168.1.0/24) instead of 0.0.0.0/0.
- DNS leak protection: configure DNS in client config and a firewall to block DNS outside the tunnel if routing all traffic.
- Use non-standard ports: change ListenPort to reduce random scanning at the cost of obscurity only.
- Monitoring:
sudo wg showand journalctl -u wg-quick@wg0 are your friends.

