Creating a WireGuard VPN Server for Secure Remote Access to Your Homelab
I've tried several VPN solutions for accessing my homelab remotely—OpenVPN, Tailscale, traditional reverse proxies—but WireGuard strikes the best balance between security, speed, and simplicity. Unlike OpenVPN with its 16,000 lines of code, WireGuard runs on just 4,000 lines of code in the kernel, making it auditable and blazing fast. When I needed a self-hosted solution I could run on a cheap VPS (you can grab one for around $40/year from providers like RackNerd), WireGuard became my go-to.
In this guide, I'll walk you through setting up a WireGuard server in Docker, generating peer configurations for your devices, and securing it properly. This approach works on any Linux server—whether that's a homelab machine or a public VPS.
Why WireGuard Over Other VPN Options?
Before we dive into the setup, let me explain why I prefer WireGuard for homelab access. First, it's modern—designed from scratch in 2015, unlike OpenVPN which dates to 2002. Second, the cryptography is hardened with WireGuard using only proven algorithms (ChaCha20, Poly1305, Curve25519). Third, it's fast—I measured throughput improvements of 3-4x over OpenVPN on the same hardware.
WireGuard also handles key rotation automatically and uses a simpler configuration model. Each peer (phone, laptop, server) gets a keypair, and the server maintains a simple list of allowed IPs. There's no complex certificate management or session negotiation—just cryptographic identities.
The tradeoff? WireGuard is less "invisible" to network monitoring since all traffic uses the same UDP port. But for homelab use, that's not a concern.
Prerequisites and Planning
You'll need:
- A Linux server (VPS, Raspberry Pi, or homelab machine) with Docker installed
- A public IP address or domain pointing to your server
- UDP port 51820 accessible (or a port of your choice)
- Client devices: phone, laptop, etc.
For this guide, I'm assuming you'll run WireGuard on a VPS. A basic VPS from RackNerd or similar providers (typically $3-4/month) is more than sufficient. I prefer running WireGuard on a separate public server rather than exposing my homelab's IP directly to the internet.
The network topology will look like this: Your homelab runs behind NAT → WireGuard server sits on a VPS with a public IP → Your phone/laptop connects to the WireGuard server → Traffic is routed back to your homelab over the tunnel.
Setting Up WireGuard with Docker
I use the linuxserver/wireguard Docker image, which handles key generation and configuration automatically. Here's my Docker Compose setup:
version: '3.8'
services:
wireguard:
image: linuxserver/wireguard:latest
container_name: wireguard
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
- PUID=1000
- PGID=1000
- TZ=America/Denver
- SERVERURL=your-server-domain.com
- SERVERPORT=51820
- PEERS=phone,laptop,tablet
- PEERDNS=8.8.8.8,8.8.4.4
- ALLOWEDIPS=10.13.13.0/24
- INTERNAL_SUBNET=10.13.13.0/24
- LOG_CONFS=true
ports:
- "51820:51820/udp"
volumes:
- /opt/wireguard/config:/config
- /lib/modules:/lib/modules:ro
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
restart: unless-stopped
This configuration creates a WireGuard server with three peer profiles (phone, laptop, tablet). Let me break down the key environment variables:
SERVERURL: The domain or IP of your VPS that clients will connect toSERVERPORT: The UDP port WireGuard listens on (default 51820)PEERS: A comma-separated list of peer names—generates one config file per peerALLOWEDIPS: The subnet range for the VPN tunnelPEERDNS: DNS servers clients will use (I often use Quad9 or Pi-hole)
Start the container:
docker-compose up -d wireguard
After startup, check the logs to confirm the keys were generated:
docker logs wireguard | grep -i "keys generated"
Accessing Your Peer Configurations
Once the container is running, WireGuard has created configuration files for each peer in /opt/wireguard/config/peer_*/. Each folder contains:
privatekey: The peer's private key (keep secret)publickey: Derived public key (shared with server)wg0.conf: Full WireGuard configuration filewg0.png: QR code for mobile clients
To retrieve a peer config for your phone:
cat /opt/wireguard/config/peer_phone/wg0.png
This PNG is a QR code you can scan directly in the WireGuard mobile app. For laptop configurations, you can copy the wg0.conf file:
cat /opt/wireguard/config/peer_laptop/wg0.conf
The config will look something like:
[Interface]
Address = 10.13.13.2/32
DNS = 8.8.8.8,8.8.4.4
PrivateKey = XXXX...
Routing Traffic Back to Your Homelab
Now here's the critical part: your WireGuard clients are connected to the VPN, but they can't reach your homelab yet. You need to configure routing.
If your homelab is on a private subnet (e.g., 192.168.1.0/24) and you want VPN clients to access it, you have two options:
- Route everything through the VPN: Set
AllowedIPs = 0.0.0.0/0in the client config (sends all traffic through the tunnel) - Route only to your homelab: Set
AllowedIPs = 10.13.13.0/24, 192.168.1.0/24(only homelab traffic goes through the tunnel)
I prefer option 2 for performance. Edit the server config to include your homelab subnet:
docker exec wireguard wg set wg0 allowed-ips 10.13.13.1/32 192.168.1.0/24
But this is temporary. To make it permanent, you'll need to modify the peers. The easier approach is to update the Docker Compose environment variable and regenerate. Alternatively, manually edit /opt/wireguard/config/wg_confs/wg0.conf and restart:
docker-compose down wireguard
# Edit the config file to add your homelab subnet
docker-compose up -d wireguard
On your homelab machine (or router), you also need to add a route back to the WireGuard subnet via your VPS gateway. If your homelab is behind a router, add this route to the router's routing table pointing to your homelab's gateway IP.
Connecting Your Devices
On iOS/Android: Download the WireGuard app from your app store, then tap the "+" button and scan the QR code from your peer config. That's it—no other configuration needed.
On Linux/Mac: Download the peer's wg0.conf file and use:
sudo wg-quick up /path/to/wg0.conf
On Windows: Download the WireGuard installer, then import the .conf file directly from the GUI.
Test connectivity by pinging a machine on your homelab:
ping 192.168.1.100
Hardening Your WireGuard Setup
WireGuard is secure by design, but a few operational practices matter:
- Firewall the VPS: Use UFW to restrict traffic to only WireGuard's UDP port and SSH. Block everything else outbound except DNS and your homelab's subnet.
- Rotate keys regularly: WireGuard doesn't enforce key rotation, so I do it manually every 6-12 months. Simply regenerate peer configs and redeploy.
- Monitor peer activity: Periodically check
docker exec wireguard wg showto see which peers are connected and their last handshake time. - Use strong DNS: I default to Quad9 (9.9.9.9) instead of Google's DNS for privacy, or use Pi-hole if you want ad blocking on your VPN.
Common Issues and Troubleshooting
If clients can't connect, verify:
- UDP port 51820 is open:
sudo netstat -uln | grep 51820 - The WireGuard container is running:
docker ps | grep wireguard - Peers are in the server config:
docker exec wireguard wg show
If you can connect to WireGuard but can't reach your homelab, check routing:
- Verify the allowed-ips include your homelab subnet
- Check that your homelab's firewall accepts traffic from the WireGuard subnet (10.13.13.0/24)
- Ensure your router has a return route to the WireGuard subnet pointing to your homelab gateway
Next Steps
Once WireGuard is running reliably, consider:
- Monitoring: Set up Uptime Kuma behind WireGuard to monitor your homelab services from anywhere
- Additional security: Combine WireGuard with Authelia or Zero Trust networking for application-level authentication
- Scaling: Add more peers or server instances as your needs grow
WireGuard has been rock-solid in my homelab for two years now. I've never had a leak or unexpected disconnect. If you're currently using a reverse proxy or Tailscale for remote access, WireGuard gives you more control and lower overhead—especially if you're paying for a VPS anyway. The setup is straightforward, and the security is modern.
Discussion