WireGuard Full Documentation

This guide explains how to install and configure a WireGuard VPN server on Ubuntu, connect clients such as Windows computers and Android phones, generate QR codes, manage multiple peers, configure routing, NAT, and port forwarding.

Introduction to WireGuard

WireGuard is a modern VPN protocol that creates an encrypted tunnel between devices. It uses public and private keys instead of usernames and passwords.

A typical setup looks like this:

Internet
    |
    |
Ubuntu Server (WireGuard Server)
Public IP: AWS EC2 Public IP
WireGuard IP: 10.0.0.1
    |
    | Encrypted VPN Tunnel
    |
Windows / Android / MikroTik Clients
10.0.0.2, 10.0.0.3, etc.

Install WireGuard on Ubuntu Server

# Update Ubuntu packages
sudo apt update

# Install WireGuard
sudo apt install wireguard -y

WireGuard configuration files are stored in:

/etc/wireguard/

The main server configuration file will be:

/etc/wireguard/wg0.conf

Check WireGuard Version

wg --version

Example output:

wireguard-tools v1.x.x

Generate Server Keys

WireGuard uses two keys:

Private Key → Secret, never share
Public Key → Shared with clients
# Go to WireGuard directory
cd /etc/wireguard

# Generate server private key
sudo wg genkey | sudo tee server_private.key

# Generate server public key
sudo cat server_private.key | wg pubkey | sudo tee server_public.key

Check the keys:

sudo cat /etc/wireguard/server_private.key

sudo cat /etc/wireguard/server_public.key

The private key stays on the server. The public key is shared with clients.

Create WireGuard Server Configuration

sudo nano /etc/wireguard/wg0.conf

Example configuration:

[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY

# Enable NAT and forwarding when WireGuard starts
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o ens5 -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 ens5 -j MASQUERADE

Replace:

SERVER_PRIVATE_KEY

with:

sudo cat /etc/wireguard/server_private.key

Replace:

ens5

with your internet interface name. For AWS EC2, it is commonly:

ens5

Check yours:

ip addr

Enable IP Forwarding

IP forwarding allows Ubuntu to route traffic between WireGuard clients and the internet.

sudo nano /etc/sysctl.conf

Add:

net.ipv4.ip_forward=1

Apply changes:

sudo sysctl -p

Verify:

cat /proc/sys/net/ipv4/ip_forward

Expected output:

1

Firewall and NAT Configuration

Allow WireGuard Port

sudo ufw allow 51820/udp
sudo ufw reload

AWS users must also allow the port in Security Group:

Type: Custom UDP Rule
Port: 51820
Source: 0.0.0.0/0

NAT Explanation

The MASQUERADE rule allows VPN clients to access the internet using the Ubuntu server public IP.

iptables -t nat -A POSTROUTING -o ens5 -j MASQUERADE

Example:

Before NAT:
Client: 10.0.0.2 → Internet

After NAT:
AWS Public IP → Internet

Start and Enable WireGuard Service

# Start WireGuard
sudo systemctl start wg-quick@wg0

# Enable at boot
sudo systemctl enable wg-quick@wg0

Check status:

systemctl status wg-quick@wg0

Check interface:

sudo wg show

Successful output should show:

interface: wg0
public key: SERVER_PUBLIC_KEY
listening port: 51820

Generate Client Keys

Every WireGuard client must have its own unique key pair. Never reuse the same private key for multiple devices.

Example clients:

Windows PC
Android Phone
Laptop
MikroTik Router

Create Client Directory

mkdir -p ~/wireguard-clients
cd ~/wireguard-clients

Generate Client 1 Keys

# Generate private key
wg genkey | tee client1_private.key

# Generate public key
cat client1_private.key | wg pubkey | tee client1_public.key

View keys:

cat client1_private.key

cat client1_public.key

Example:

client1_private.key
xxxxxxxxxxxxxxxxxxxxxxxxxxxx=

client1_public.key
yyyyyyyyyyyyyyyyyyyyyyyyyyyy=

The private key goes to the client device. The public key is added to the Ubuntu server.

Add Client Peer to WireGuard Server

A peer tells the server: "Allow this device to connect using this public key and assign it this VPN IP."

Edit Server Configuration

sudo nano /etc/wireguard/wg0.conf

Add the client at the bottom:

[Peer]
# Client 1
PublicKey = CLIENT1_PUBLIC_KEY
AllowedIPs = 10.0.0.2/32

Replace:

CLIENT1_PUBLIC_KEY

with:

cat ~/wireguard-clients/client1_public.key

Restart WireGuard:

sudo systemctl restart wg-quick@wg0

Configure WireGuard Client on Windows

Install Application

Download and install the WireGuard Windows application.

Create Tunnel

WireGuard Application

Add Tunnel

Add empty tunnel

The application automatically creates a private key.

Example configuration:

[Interface]
PrivateKey = CLIENT_PRIVATE_KEY
Address = 10.0.0.2/24
DNS = 1.1.1.1

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

Configuration Explanation

Address = 10.0.0.2/24
Client VPN address

PublicKey
Ubuntu server public key

Endpoint
Ubuntu server public IP and port

AllowedIPs = 0.0.0.0/0
Send all internet traffic through VPN

PersistentKeepalive = 25
Keeps tunnel alive behind NAT

Add Windows Public Key to Server

Copy the public key from WireGuard Windows application.

Add it to Ubuntu:

sudo nano /etc/wireguard/wg0.conf
[Peer]
PublicKey = WINDOWS_PUBLIC_KEY
AllowedIPs = 10.0.0.2/32
Restart:
sudo systemctl restart wg-quick@wg0

Configure WireGuard Client on Android

Android uses the same configuration as Windows. The easiest method is importing using a QR code.

Install:

WireGuard App
Google Play Store

Create Client Configuration File

nano ~/wireguard-clients/client1.conf

Example:

[Interface]
PrivateKey = CLIENT1_PRIVATE_KEY
Address = 10.0.0.2/24
DNS = 1.1.1.1

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

Insert client private key:

cat ~/wireguard-clients/client1_private.key

Insert server public key:

sudo wg show wg0 public-key

Generate WireGuard QR Code

Install qrencode

sudo apt update
sudo apt install qrencode -y

Display QR Code in Terminal

qrencode -t ansiutf8 < ~/wireguard-clients/client1.conf

Open WireGuard Android application:

WireGuard App

Add Tunnel

Scan from QR Code

Create QR Image File

qrencode -o client1.png < ~/wireguard-clients/client1.conf

The PNG contains the complete WireGuard configuration.

WARNING:
The QR code contains the client private key.
Anyone who scans it can connect as that client.

Verify Client Connection

Activate the client tunnel, then check Ubuntu:

sudo wg show

Successful connection:

peer: CLIENT_PUBLIC_KEY
endpoint: CLIENT_IP:PORT
latest handshake: few seconds ago
transfer: received, sent

A handshake proves that the encrypted tunnel is established.

Managing Multiple WireGuard Peers

WireGuard supports multiple clients connected to one server. Each device must have its own private key, public key, and VPN IP address.

Example network design:

WireGuard Server
wg0: 10.0.0.1/24

Client 1 - Windows PC
10.0.0.2

Client 2 - Android Phone
10.0.0.3

Client 3 - Laptop
10.0.0.4

Client 4 - MikroTik Router
10.0.0.5

Never assign the same VPN IP to two different clients.

Client IP Allocation Planning

A simple method is assigning addresses sequentially.

Server:
10.0.0.1

Windows:
10.0.0.2

Android:
10.0.0.3

Laptop:
10.0.0.4

Router:
10.0.0.5

Server configuration example:

[Peer]
# Windows PC
PublicKey = WINDOWS_PUBLIC_KEY
AllowedIPs = 10.0.0.2/32

[Peer]
# Android Phone
PublicKey = ANDROID_PUBLIC_KEY
AllowedIPs = 10.0.0.3/32

[Peer]
# Laptop
PublicKey = LAPTOP_PUBLIC_KEY
AllowedIPs = 10.0.0.4/32

Recommended Client File Organization

~/wireguard-clients/

├── windows.conf
├── windows_private.key
├── windows_public.key

├── android.conf
├── android_private.key
├── android_public.key

└── laptop.conf
    ├── laptop_private.key
    └── laptop_public.key

Using names like windows, android, and office-laptop is easier than using only client1, client2.

Full Tunnel VPN Configuration

A full tunnel means all client internet traffic goes through the WireGuard server.

Client configuration: [Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = SERVER_IP:51820
AllowedIPs = 0.0.0.0/0

Traffic flow:

Client
10.0.0.2
    |
    v
WireGuard Server
10.0.0.1
    |
    v
Internet

The internet sees the Ubuntu server public IP instead of the client's real IP.

Split Tunnel Configuration

Split tunnel sends only VPN traffic through WireGuard. Normal internet traffic uses the client's local connection.

[Peer]
PublicKey = SERVER_PUBLIC_KEY
AllowedIPs = 10.0.0.0/24

Example:

Access server: 10.0.0.1 → VPN tunnel Google: 8.8.8.8 → Normal internet

Port Forwarding to WireGuard Clients

You can expose a service running on a WireGuard client through the Ubuntu server.

Example:

Internet User
|
| Port 80
v
Ubuntu Server
Public IP
|
| WireGuard
v
Client PC
10.0.0.2:80

Enable Forwarding

cat /proc/sys/net/ipv4/ip_forward

Expected:

1

Add DNAT Rule

sudo iptables -t nat -A PREROUTING \ -i ens5 \ -p tcp \ --dport 80 \ -j DNAT \ --to-destination 10.0.0.2:80

Explanation:

ens5
Internet interface

80
Incoming HTTP port

10.0.0.2:80
Destination client web server

Allow Forward Traffic

sudo iptables -A FORWARD \ -p tcp \ -d 10.0.0.2 \ --dport 80 \ -m conntrack \ --ctstate NEW,ESTABLISHED,RELATED \ -j ACCEPT

Allow Return Traffic

sudo iptables -A FORWARD \ -p tcp \ -s 10.0.0.2 \ --sport 80 \ -m conntrack \ --ctstate ESTABLISHED,RELATED \ -j ACCEPT

The first rule allows requests to reach the client. The second allows responses to return.

AWS EC2 WireGuard Configuration

When running WireGuard on AWS, there are two firewalls:

1. AWS Security Group
2. Ubuntu Firewall (UFW)

AWS Security Group

Inbound Rule: Type: Custom UDP Port: 51820 Source: 0.0.0.0/0

For port forwarding:

HTTP TCP 80
Source: 0.0.0.0/0

Check AWS Interface

ip addr

AWS Ubuntu usually uses:

ens5

MikroTik WireGuard Client

WireGuard support requires RouterOS 7 or newer. RouterOS 6 does not include native WireGuard.

Create Interface

/interface wireguard add name=wg1

Add IP Address

/ip address add address=10.0.0.5/24 interface=wg1

Add Ubuntu Peer

/interface wireguard peers add interface=wg1 \ public-key="SERVER_PUBLIC_KEY" \ endpoint-address=SERVER_IP \ endpoint-port=51820 \ allowed-address=0.0.0.0/0 \ persistent-keepalive=25

Add MikroTik Public Key to Ubuntu

[Peer]
PublicKey = MIKROTIK_PUBLIC_KEY
AllowedIPs = 10.0.0.5/32

WireGuard Troubleshooting

When WireGuard does not connect, troubleshoot in the following order:

1. Check service status
2. Check keys
3. Check firewall
4. Check routing
5. Check handshake
6. Check NAT

Check WireGuard Service Status

sudo systemctl status wg-quick@wg0

Successful output:

Active: active (exited)

If failed:

Active: failed (Result: exit-code)

View detailed error:

sudo journalctl -u wg-quick@wg0 -n 50

Check WireGuard Interface

sudo wg show

Example working output:

interface: wg0
public key: SERVER_PUBLIC_KEY
listening port: 51820

peer: CLIENT_PUBLIC_KEY
endpoint: CLIENT_IP:PORT
latest handshake: 20 seconds ago
transfer: received 1.2 MiB, sent 500 KiB

Important values:

latest handshake
Shows whether the client is connected.

transfer
Shows whether data is moving.

Problem: No Handshake

If you see:

latest handshake: never

Check the following.

1. Check Server Port

sudo ss -ulnp | grep 51820

Expected:

udp UNCONN 0 0 0.0.0.0:51820

2. Check AWS Security Group

Inbound: UDP 51820 Source: 0.0.0.0/0

3. Check UFW

sudo ufw status
Allow WireGuard:
sudo ufw allow 51820/udp

4. Check Client Endpoint

Endpoint = SERVER_PUBLIC_IP:51820
Common mistakes:
Wrong: Endpoint = 10.0.0.1:51820 Correct: Endpoint = AWS_PUBLIC_IP:51820

UFW Permission Error

A common error:

/usr/bin/wg-quick: line 295: /usr/sbin/ufw: Permission denied

Cause:

wg-quick is trying to execute UFW commands, but UFW permissions are incorrect.

Check UFW permissions:

ls -l /usr/sbin/ufw

Correct permission example:

-rwxr-xr-x

Fix:

sudo chmod 755 /usr/sbin/ufw

Restart:

sudo systemctl restart wg-quick@wg0

Check IP Forwarding

cat /proc/sys/net/ipv4/ip_forward

Correct:

1

Enable permanently:

sudo nano /etc/sysctl.conf
Add:
net.ipv4.ip_forward=1
Apply:
sudo sysctl -p

Check iptables Rules

sudo iptables -L -v
Check NAT:
sudo iptables -t nat -L -v
Expected:
MASQUERADE out-interface ens5

Make iptables Rules Persistent

iptables rules disappear after reboot unless saved.

Install persistence package:
sudo apt install iptables-persistent -y
Save current rules:
sudo netfilter-persistent save
Restore automatically:
sudo systemctl enable netfilter-persistent

Check Logs

WireGuard Logs

sudo journalctl -u wg-quick@wg0
Follow live:
sudo journalctl -u wg-quick@wg0 -f

Kernel Logs

sudo dmesg | grep wireguard

WireGuard Security Best Practices

1. Protect Private Keys

sudo chmod 600 /etc/wireguard/*.key
Never share:
server_private.key client_private.key
Only share:
public keys

2. Use Unique Keys

Wrong: Windows + Android same private key Correct: Windows private key 1 Android private key 2

3. Remove Lost Devices

If a phone or laptop is lost, remove its peer.

Edit:
sudo nano /etc/wireguard/wg0.conf
Delete:
[Peer] PublicKey = LOST_DEVICE_KEY AllowedIPs = 10.0.0.x/32
Restart:
sudo systemctl restart wg-quick@wg0

Backup WireGuard Configuration

Backup folder:
sudo cp -r /etc/wireguard ~/wireguard-backup
Compress:
tar -czvf wireguard-backup.tar.gz /etc/wireguard

Useful WireGuard Commands

# Start
sudo systemctl start wg-quick@wg0

# Stop
sudo systemctl stop wg-quick@wg0

# Restart
sudo systemctl restart wg-quick@wg0

# Enable startup
sudo systemctl enable wg-quick@wg0

# Show status
sudo wg show

# Bring interface up manually
sudo wg-quick up wg0

# Bring interface down
sudo wg-quick down wg0

Production Deployment Checklist

✓ Ubuntu updated
✓ WireGuard installed
✓ Server keys generated
✓ Client keys generated
✓ UDP 51820 opened
✓ AWS Security Group configured
✓ IP forwarding enabled
✓ NAT configured
✓ Firewall tested
✓ Clients connected
✓ Handshake verified
✓ Private keys protected
✓ Configuration backed up

Final Network Example

Internet | | AWS Ubuntu Server | Public IP | WireGuard wg0 10.0.0.1 | --------------------- | | | Windows Android MikroTik 10.0.0.2 10.0.0.3 10.0.0.5

This completes the WireGuard server and client deployment guide.