0) Goals we achieved
- Main server runs WireGuard server (
wg0) - Pi1 + Pi2 run WireGuard clients
- Split tunnel (VPN traffic only; internet stays normal/fast)
- AdGuard Home runs on a Pi and keeps DNS control (no WG DNS override)
- Optional: Monitor Docker hosts from Uptime Kuma over WireGuard
- IPv6 permanently disabled (optional)
- UFW firewall locked down with only the ports you want public
1) WireGuard on the Main Server (Server side)
1.1 Install
sudo apt update
sudo apt install -y wireguard
1.2 Generate keys
wg genkey | sudo tee /etc/wireguard/server.key | wg pubkey | sudo tee /etc/wireguard/server.pub >/dev/null
sudo chmod 600 /etc/wireguard/server.key
1.3 Create /etc/wireguard/wg0.conf
sudo nano /etc/wireguard/wg0.conf
Paste:
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
Insert the private key:
sudo cat /etc/wireguard/server.key
1.4 Enable + start
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo wg
2) WireGuard on Raspberry Pi 1 and Pi 2 (Client side)
Do this on each Pi, changing the IP.
2.1 Install
sudo apt update
sudo apt install -y wireguard
2.2 Generate keys
wg genkey | tee ~/client.key | wg pubkey > ~/client.pub
chmod 600 ~/client.key
2.3 Create /etc/wireguard/wg0.conf
Pi1 config (10.8.0.2)
sudo nano /etc/wireguard/wg0.conf
[Interface]
Address = 10.8.0.2/24
PrivateKey = <PI1_PRIVATE_KEY>
# IMPORTANT: No DNS line (because you run AdGuard)
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = <SERVER_PUBLIC_IP>:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25
Pi2 config (10.8.0.3)
Same, but:
Address = 10.8.0.3/24
PrivateKey = <PI2_PRIVATE_KEY>
✅ Critical split tunnel rule:
AllowedIPs = 10.8.0.0/24
❌ Do NOT use .../0 or 0.0.0.0/0.
2.4 Start on each Pi
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo wg
3) Add Pi peers to the Main Server
On the main server, open:
sudo nano /etc/wireguard/wg0.conf
Add:
[Peer]
PublicKey = <PI1_PUBLIC_KEY>
AllowedIPs = 10.8.0.2/32
[Peer]
PublicKey = <PI2_PUBLIC_KEY>
AllowedIPs = 10.8.0.3/32
Restart:
sudo systemctl restart wg-quick@wg0
sudo wg
4) Verify split tunnel is correct
4.1 Tunnel ping tests
From Pi1/Pi2:
ping 10.8.0.1
From server:
ping 10.8.0.2
ping 10.8.0.3
4.2 Confirm internet stays normal (split tunnel)
On Pi2:
ip route
You should see:
- default route via your LAN gateway (ex:
192.168.x.1) 10.8.0.0/24 dev wg0
If you ever see default via wg0, you accidentally full-tunneled.
5) DNS note (AdGuard Home on Pi)
You fixed this correctly.
✅ If AdGuard runs on the Pi, do NOT set DNS = ... in the WG config.
Because WireGuard would override system DNS and break resolution.
6) Optional: Disable IPv6 permanently (Ubuntu / Pi)
6.1 Sysctl method (recommended)
sudo nano /etc/sysctl.d/99-disable-ipv6.conf
Paste:
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
Apply:
sudo sysctl --system
Verify:
ip a | grep inet6
7) Firewall (UFW) with your current public ports (22, 80, 443)
7.1 Reset + defaults
sudo ufw disable
sudo ufw reset
sudo ufw default deny incoming
sudo ufw default allow outgoing
7.2 Allow required ports
SSH (choose one)
Safer (WireGuard only):
sudo ufw allow from 10.8.0.0/24 to any port 22 proto tcp comment "SSH via WireGuard"
Or if public SSH is needed:
sudo ufw limit 22/tcp comment "SSH rate limit"
HTTP/HTTPS:
sudo ufw allow 80/tcp comment "HTTP"
sudo ufw allow 443/tcp comment "HTTPS"
WireGuard port:
sudo ufw allow 51820/udp comment "WireGuard"
sudo ufw allow in on wg0 comment "WireGuard tunnel"
7.3 Enable
sudo ufw enable
sudo ufw status numbered
sudo ufw status verbose
8) Optional: Docker monitoring over WireGuard (Uptime Kuma)
8.1 Install docker socket proxy on each Pi (recommended)
Create docker-compose.yml:
version: "3.8"
services:
docker-socket-proxy:
image: tecnativa/docker-socket-proxy
container_name: docker-socket-proxy
ports:
- "2375:2375"
environment:
CONTAINERS: 1
INFO: 1
PING: 1
VERSION: 1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
Run:
docker compose up -d
8.2 Firewall: allow Docker proxy ONLY over WireGuard
On each Pi:
sudo ufw allow from 10.8.0.0/24 to any port 2375 comment "Docker API via WireGuard only"
8.3 Add in Uptime Kuma
- Monitor Type: Docker Host
- URL:
http://10.8.0.2:2375http://10.8.0.3:2375
9) What NOT to do (the pitfalls we hit)
- ❌ Don’t expose Docker
2375publicly - ❌ Don’t use
AllowedIPs = .../0(that becomes full tunnel) - ❌ Don’t set
DNS = 10.8.0.1unless server truly runs DNS - ❌ Don’t rely on Certbot/Caddy to “secure Docker API” (wrong model)
- ✅ Use WireGuard + firewall instead
Quick “health checklist” commands
On any node:
sudo wg
ip route
sudo ufw status verbose
ss -tulpen | head -n 30
If you want, I can also generate a one-page printable version of this runbook with:
- blanks for keys/IPs
- checkboxes
- and “expected outputs” for each command.
Leave a Reply