WireGuard VPN for admin access
Set up WireGuard on a VPS so you (and only you) can reach internal services without exposing them to the internet.
WireGuard VPN for admin access
Once your VPS is in production, you don’t want to expose admin UIs (Grafana, Netdata, internal tools) to the public internet. WireGuard gives you a private tunnel to your VPS — only clients with the right keys can reach those services.
Server setup
apt install -y wireguard
# Generate server keys
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
chmod 600 /etc/wireguard/server_private.key
# Server config
cat > /etc/wireguard/wg0.conf <<EOF
[Interface]
Address = 10.10.10.1/24
ListenPort = 51820
PrivateKey = $(cat /etc/wireguard/server_private.key)
# Forward traffic from VPN clients
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer]
# admin-laptop
PublicKey = <client_public_key>
AllowedIPs = 10.10.10.2/32
EOF
# Enable IP forwarding
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
systemctl enable --now wg-quick@wg0
# Open firewall
ufw allow 51820/udp comment 'WireGuard'
Client setup (macOS, Linux, iOS, Android)
For each client:
- Generate keys:
wg genkey | tee private.key | wg pubkey > public.key - Add the client’s public key to
/etc/wireguard/wg0.confunder a new[Peer]block - Restart:
systemctl restart wg-quick@wg0 - Give the client the config:
[Interface]
PrivateKey = <client_private_key>
Address = 10.10.10.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = <server_public_key>
Endpoint = <server_public_ip>:51820
AllowedIPs = 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 10.10.10.0/24
PersistentKeepalive = 25
AllowedIPs controls which traffic goes through the VPN. The ranges above
route only private network traffic — your regular browsing stays direct.
Restrict admin UIs to VPN
Now lock down the admin ports. Edit Caddyfile or your reverse proxy to only
listen on 10.10.10.0/24:
netdata.internal {
bind 10.10.10.1
reverse_proxy localhost:19999
}
Or simpler with iptables:
# Block Netdata from public internet
iptables -A INPUT -p tcp --dport 19999 ! -s 10.10.10.0/24 -j DROP
Why WireGuard (not OpenVPN)?
- Faster: ~3× throughput on the same hardware
- Simpler: ~4,000 lines of kernel code vs OpenVPN’s ~100,000
- Modern crypto: Curve25519, ChaCha20, Poly1305
- Stealthier: No response to unauthenticated packets — invisible to port scans
The one tradeoff: no built-in dynamic IP support. For that, you need
wireguard-dynamic or a small script.