Andrey's Blog

WireGuard + AdGuard Home

Why WireGuard?

WireGuard is a modern VPN protocol built into the Linux kernel. Compared to OpenVPN or IPSec it has a much smaller codebase (~4000 lines vs ~100,000), making it easier to audit and less likely to contain vulnerabilities. It’s also significantly faster and simpler to configure.

Key advantages:


Prerequisites


Step 1 — Install WireGuard

sudo apt update
sudo apt install -y wireguard wireguard-tools qrencode

Step 2 — Generate Server Keys

# Generate server key pair
wg genkey | \
sudo tee /etc/wireguard/server_private.key | \
wg pubkey \
| sudo tee /etc/wireguard/server_public.key

# Secure the private key
sudo chmod 600 /etc/wireguard/server_private.key

# View and save both keys
sudo cat /etc/wireguard/server_private.key   # keep secret — server only
sudo cat /etc/wireguard/server_public.key    # share with clients

Step 3 — Generate Client Keys

Repeat for each device. Example for two devices:

# Client 1 (laptop)
wg genkey | \
sudo tee /etc/wireguard/client1_private.key | \
wg pubkey | \
sudo tee /etc/wireguard/client1_public.key

sudo chmod 600 /etc/wireguard/client1_private.key

# Client 2 (phone)
wg genkey | \
sudo tee /etc/wireguard/client2_private.key | \
wg pubkey | \
sudo tee /etc/wireguard/client2_public.key

sudo chmod 600 /etc/wireguard/client2_private.key

Step 4 — Find Your Network Interface

Before writing the config, check your server’s network interface name:

ip route | grep default

Look for dev ethX or dev ensX in the output. Replace eth0 in all configs below with your actual interface name.


Step 5 — Create Server Configuration

sudo nano /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
MTU = 1380

# IP forwarding
PostUp = sysctl -w net.ipv4.ip_forward=1

[Peer]
# Laptop
PublicKey = <CLIENT1_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32

[Peer]
# Phone
PublicKey = <CLIENT2_PUBLIC_KEY>
AllowedIPs = 10.0.0.3/32

Note: NAT and forwarding rules are handled by UFW’s before.rules (see Step 7), not PostUp. This is cleaner and more reliable across reboots.


Step 6 — Enable IP Forwarding Permanently

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

Step 7 — Configure UFW

Allow WireGuard port

sudo ufw allow 51820/udp
sudo ufw allow in on wg0 to any port 53    # AdGuard Home DNS

Edit before.rules for NAT and forwarding

sudo nano /etc/ufw/before.rules

Add this block at the very top of the file, before the *filter line:

# WireGuard NAT
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
COMMIT

Then find the *filter section and locate :ufw-before-forward - [0:0]. Add these two lines directly below it:

-A ufw-before-forward -i wg0 -j ACCEPT
-A ufw-before-forward -o wg0 -j ACCEPT

Also set the default forward policy:

sudo nano /etc/default/ufw

Change:

DEFAULT_FORWARD_POLICY="DROP"

To:

DEFAULT_FORWARD_POLICY="ACCEPT"

Reload UFW:

sudo ufw reload

Step 8 — Start WireGuard

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0

# Verify
sudo wg show

You should see the wg0 interface with your server public key and peers listed.


Step 9 — Install AdGuard Home

curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v

Complete the setup wizard

AdGuard Home starts on port 3000 after installation. Create an SSH tunnel on your local machine to access it:

ssh -L 3000:127.0.0.1:3000 <User>@<YOUR_SERVER_IP>

Open http://localhost:3000 in your browser and complete the wizard:

StepSetting
Admin Web Interface127.0.0.1 : 3000
DNS Server10.0.0.1 : 53

Setting DNS to 10.0.0.1 binds AdGuard Home to the WireGuard interface only — it will never be reachable from the public internet.

After completing the wizard, set the admin password and finish.


Step 10 — Configure Encrypted Upstream DNS

Access the web UI via the SSH tunnel, then go to Settings → DNS Settings.

Set upstream DNS to:

tls://1.1.1.1          # Cloudflare DoT (fastest)
tls://1.0.0.1          # Cloudflare DoT (backup)
tls://dns.quad9.net    # Quad9 DoT (malware blocking, good privacy)

Set bootstrap DNS to:

1.1.1.1
9.9.9.9

Click Test upstreams → all green → Apply.

This lets you access the UI at http://10.0.0.1:3000 whenever you’re connected to the VPN, without needing an SSH tunnel each time:

sudo systemctl stop AdGuardHome
sudo nano /opt/AdGuardHome/AdGuardHome.yaml

Find and change:

http:
  address: 127.0.0.1:3000

To:

http:
  address: 10.0.0.1:3000
sudo systemctl start AdGuardHome
sudo ufw allow in on wg0 to any port 3000

Step 11 — Create Client Config Files

sudo mkdir -p /etc/wireguard/clients

Client 1 — Laptop

sudo nano /etc/wireguard/clients/client1.conf
[Interface]
PrivateKey = <CLIENT1_PRIVATE_KEY>
Address = 10.0.0.2/32
DNS = 10.0.0.1
MTU = 1380

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

Client 2 — Phone

sudo nano /etc/wireguard/clients/client2.conf
[Interface]
PrivateKey = <CLIENT2_PRIVATE_KEY>
Address = 10.0.0.3/32
DNS = 10.0.0.1
MTU = 1380

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

No inline comments in config files — some clients (especially iOS) fail to parse them.


Step 12 — Deploy Configs to Devices

iOS / Android — QR Code

sudo cat /etc/wireguard/clients/client2.conf | qrencode -t ansiutf8

Install the WireGuard app, tap +Scan QR code.

Linux (SCP)

Run on your local machine:

scp <User>@<SERVER_IP>:/etc/wireguard/clients/client1.conf ~/client1.conf
sudo cp ~/client1.conf /etc/wireguard/

Step 13 — Arch Linux Client Setup

sudo pacman -S wireguard-tools
sudo cp ~/client1.conf /etc/wireguard/
sudo chmod 600 /etc/wireguard/client1.conf

Fix DNS with systemd-resolved

Arch uses systemd-resolved which intercepts DNS and ignores WireGuard’s DNS = setting by default. Add these hooks to your config:

sudo nano /etc/wireguard/client1.conf

Add to the [Interface] section:

PostUp = resolvectl dns client1 10.0.0.1; resolvectl domain client1 "~."
PostDown = resolvectl dns client1 ""; resolvectl domain client1 ""

Start the tunnel

# Start manually
sudo wg-quick up client1

# Enable on boot
sudo systemctl enable wg-quick@client1
sudo systemctl start wg-quick@client1

# Verify DNS is correct
resolvectl status client1

Expected output:

Current DNS Server: 10.0.0.1
DNS Domain: ~.
Default Route: yes

Useful commands

sudo wg show                             # tunnel status
sudo wg-quick up client1                 # connect
sudo wg-quick down client1               # disconnect
sudo systemctl restart wg-quick@client1  # restart

Adding More Devices

Generate a new key pair on the server:

wg genkey | \
sudo tee /etc/wireguard/client3_private.key | \
wg pubkey | \
sudo tee /etc/wireguard/client3_public.key

Add a new [Peer] block to wg0.conf:

[Peer]
# New device
PublicKey = <CLIENT3_PUBLIC_KEY>
AllowedIPs = 10.0.0.4/32

Reload without dropping existing connections:

sudo wg syncconf wg0 <(sudo wg-quick strip wg0)

DNS Blocklists (Filters → DNS Blocklists)

ListPurpose
AdGuard DNS filterAds + trackers
uBlock₀ Badware risksMalware domains
Phishing ArmyPhishing sites

DNS Settings (Settings → DNS Settings)

General Settings

Per-Device Tracking (Settings → Client Settings)

Add named clients for per-device statistics:

10.0.0.2 → Laptop
10.0.0.3 → Phone

Verify Everything Works

On the server

# WireGuard status and connected peers
sudo wg show

# AdGuard Home listening on WireGuard interface only
sudo ss -tulpn | grep :53
# Must show 10.0.0.1:53 — NOT 0.0.0.0:53

# Firewall rules
sudo ufw status verbose

# All services running
sudo systemctl status wg-quick@wg0 AdGuardHome

From a connected device

  1. https://ifconfig.me → should show your server IP
  2. https://ipleak.net → DNS should show your server IP (no leaks)
  3. http://10.0.0.1:3000 → AdGuard Home dashboard accessible

Final Port/Service Overview

ServiceProtocolPortAccessible from
WireGuardUDP51820Public internet
SSHTCP22Public internet
AdGuard Home DNSUDP/TCP53VPN only (10.0.0.1)
AdGuard Home UITCP3000VPN only (10.0.0.1)

Maintenance

Update AdGuard Home

/opt/AdGuardHome/AdGuardHome --update
sudo systemctl restart AdGuardHome

Update WireGuard

sudo apt update && sudo apt upgrade wireguard-tools

Backup configs

sudo cp /etc/wireguard/wg0.conf ~/wg0-backup.conf
sudo cp /opt/AdGuardHome/AdGuardHome.yaml ~/adguard-backup.yaml

Revoke a device

Remove its [Peer] block from wg0.conf, then:

sudo wg syncconf wg0 <(sudo wg-quick strip wg0)

Key Points to Remember