Skip to main content

WireGuard VPN: Complete Setup Guideor Server and Clients

Created: March 10, 2026 6 min read

uction

e walks through a complete server + client setup.

Prerequisites: Ubuntu 20.04+ server with a public IP, sudo access.

Server Setup

Step 1: Install WireGuard

# Ubuntu 20.04+
sudo apt update && sudo apt install wireguard

# Verify kernel module
lsmod | grep wireguard
# wireguard              94208  0

Step 2: Generate Server Keys

# Generate key pair
wg genkey | sudo tee /etc/wireguard/server_private.key | \
erver_public.key

# Set permissions
sudo chmod 600 /etc/wireguard/server_private.key

# View the keys
sudo cat /etc/wireguard/server_private.key
sudo cat /etc/wireguard/server_public.key

Step 3: Create Server Config

sudo nano /etc/wireguard/wg0.conf
[Interface]
# Server's VPN IP address
Address = 10.0.0.1/24

# Port WireGuard listens on
ListenPort = 51820

# Server's private key
PrivateKey = <paste server_private.key here>

# Enable IP forwarding and NAT for client internet access
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# Client 1 (add more [Peer] sections for each client)
[Peer]
# Client's public key
PublicKey = <client1_public_key>
# IP address assigned to this client
AllowedIPs = 10.0.0.2/32

# Client 2
[Peer]
PublicKey = <client2_public_key>
AllowedIPs = 10.0.0.3/32

Step 4: Enable IP Forwarding

# Enable now
sudo sysctl -w net.ipv4.ip_forward=1

# Make permanent
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Step 5: Start WireGuard

enable on boot
sudo systemctl enable --now wg-quick@wg0

# Check status
do systemctl status wg-quick@wg0
sudo wg show wg0

Expected output:

interface: wg0
  public key: <server_public_key>
  private key: (hidden)
  listening port: 51820

peer: <client1_public_key>
  allowed ips: 10.0.0.2/32

Step 6: Open Firewall

# UFW
sudo ufw allow 51820/udp
sudo ufw allow OpenSSH  # don't lock yourself out!

# iptables directly
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT

Client Setup

Linux Client

# Install
sudo apt install wireguard

# Generate client keys
wg genkey | tee client_private.key | wg pubkey > client_public.key

# Create config
sudo nano /etc/wireguard/wg0.conf
[Interface]
# Client's VPN IP
Address = 10.0.0.2/24
# Client's private key
PrivateKey = <client_private_key>
# Us DNS server
DNS = 1.1.1.1

[Peer]
# Server's public key
PublicKey = <server_public_key>
# Server's address and port
Endpoint = YOUR_SERVER_IP:51820
# Route all traffic through VPN (full tunnel)
AllowedIPs = 0.0.0.0/0, ::/0
/algo)
ard automation](https://github.com/trailofbitss://github.com/wg-easy/wg-easy)
- [Algo VPN — WireGuges/man8/wg.8.html)
- [wg-easy — Web UI for WireGuard](http Page](https://man7.org/linux/man-pa/quickstart/)
- [WireGuard Mancode -t ansiutf8 < "${CLIENT_NAME}.conf"

Resources

  • [WireGuard Quick Start](https://www.wireguard.com"Client config saved to ${CLIENT_NAME}.conf" echo "Public key: $CLIENT_PUBLIC"

Generate QR code for mobile

qrenPOINT AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25 EOF

echo _KEY Endpoint = $SERVER_ENDNS = 1.1.1.1

[Peer] PublicKey = $SERVER_PUBLIC"${CLIENT_NAME}.conf" « EOF [Interface] Address = ${CLIENT_IP}/24 PrivateKey = $CLIENT_PRIVATE D [Peer] PublicKey = $CLIENT_PUBLIC AllowedIPs = ${CLIENT_IP}/32 EOF

Generate client config

cat > et wg0 peer “$CLIENT_PUBLIC" allowed-ips "${CLIENT_IP}/32”

Append to server config

sudo tee -a /etc/wireguard/wg0.conf « EOF

$CLIENT_NAME=$(wg genkey)

CLIENT_PUBLIC=$(echo "$CLIENT_PRIVATE" | wg pubkey)

Add to server

sudo wg svpn.example.com:51820" CLIENT_NAME=$1 CLIENT_IP=$2 # e.g., 10.0.0.5

Generate keys

CLIENT_PRIVATEent.sh — generate config for a new client

SERVER_PUBLIC_KEY=$(sudo cat /etc/wireguard/server_public.key) SERVER_ENDPOINT="

Automating Client Config Generation

#!/bin/bash
# generate-clirewall, check AllowedIPs, check IP forwarding

terface: No such device" → module not loaded: sudo modprobe wireguard

No traffic flowing → check fissues:

“RTNETLINK answers: Operation not permitted” → need sudo

“Unable to access intl -u wg-quick@wg0 -f

Common i10.0.0.1 # ping server from client

traceroute 8.8.8.8 # verify traffic goes through VPN

Check logs

sudo journalcable main | grep wg0

Test connectivity

ping time stats watch -n 1 ‘sudo wg show’

Check routing table

ip route show teceived, 456 MiB sent

Watch real-wg0

Check if traffic is flowing

sudo wg show wg0 transfer

peer:

transfer: 1.23 GiB rhow specific interface

sudo wg show ```

Monitoring and Troubleshooting

# Show all peers and their status
sudo wg show

# Soint = office.example.com:51820
AllowedIPs = 10.0.0.1/32, 192.168.1.0/24  # office VPN IP + office subnet
PersistentKeepalive = 25

# Office server
PublicKey = <office_public_key>
Endp[Interface]
Address = 10.0.0.2/24
ListenPort = 51820
PrivateKey = <cloud_private_key>

[Peer]2.16.0.0/24  # cloud VPN IP + cloud subnet
PersistentKeepalive = 25
# Cloud server (172.16.0.0/24)
office_private_key>

[Peer]
# Cloud server
PublicKey = <cloud_public_key>
Endpoint = cloud.example.com:51820
AllowedIPs = 10.0.0.2/32, 17rver (192.168.1.0/24)
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <
## Site-to-Site Configuration

Connect two networks (e.g., office + cloud):

Office seS only for internal domains

DNS = 10.0.0.1

Some clients support: DNS = 10.0.0.1, 1.1.1.1

ent config — use VPN DNdomain=vpn.internal

Split DNS (different DNS for VPN vs internet)

# Cli on the VPN
# On server: install and configure dnsmasq
sudo apt install dnsmasq

# /etc/dnsmasq.conf
listen-address=10.0.0.1
bind-interfaces
ace]
DNS = 10.0.0.1  # point to your DNS server

Client config

[Interfwg set wg0 peer <client_public_key> remove

Also remove from config file


## DNS Configuration

### Use Pi-hole or Custom DNS10/32

Remove a Peer

# Remove from running server
sudo guard/wg0.conf
# Add:
# [Peer]
# PublicKey = <new_client_public_key>
# AllowedIPs = 10.0.0.w_client_public.key) allowed-ips 10.0.0.10/32

# Also add to config file for persistence
sudo nano /etc/wireey

# Add peer to running server (no restart needed)
sudo wg set wg0 peer $(cat nePN.

## Adding and Removing Peers

### Add a New Client (Without Restarting)

Generate keys for new client

wg genkey | tee new_client_private.key | wg pubkey > new_client_public.kormance — only corporate traffic goes through Vom/blog/2021/03/wireguard-allowedips-calculator/


Split tunneling is better for perfhing EXCEPT specific IPs
## Use a split tunnel calculator: https://www.procustodibus.cy route corporate network through VPN

AllowedIPs = 10.0.0.0/8, 192.168.1.0/24

## Route everytthrough VPN)

In [Peer] section:

AllowedIPs = 0.0.0.0/0, ::/0


All internet traffic goes through the VPN server. Use for: public WiFi protection, bypassing geo-restrictions.

### Split Tunnel (only route specific networks)

Onlsiutf8 < /etc/wireguard/client.conf

## Split Tunneling vs Full Tunnel

### Full Tunnel (route all traffic  "+""Create from QR code" or "Create from file"
3. Generate QR code from config:

Generate QR code for mobile import

sudo apt install qrencode qrencode -t anGuard”

### iOS / Android

1. Install WireGuard from App Store / Play Store
2. Tapient

Homebrew

brew install wireguard-tools

Or download the App Store app: “Wiree client config (same format as Linux)

  1. Click “Activate”

macOS Clwww.wireguard.com/install/)

  1. Click “Add Tunnel” → “Add empty tunnel”
  2. Paste thnnect on boot sudo systemctl enable wg-quick@wg0
### Windows Client

1. Download from [wireguard.com/install](https://.me  # should show server's IP

# Disconnect
sudo wg-quick down wg0

# Auto-co
PersistentKeepalive = 25
# Connect
sudo wg-quick up wg0

# Verify connection
ping 10.0.0.1  # ping server
curl ifconfig# Keep NAT mapping alive

Comments

Share this article

Scan to read on mobile