Inside a privileged Debian 12 LXC on Proxmox VE 8, wireguard-tools and a wg0.conf at 10.10.0.1/24 listening on UDP 51820 are the entire server, since the kernel module comes from the Proxmox host rather than the container. Clients take 10.10.0.2 upward with PersistentKeepalive 25, a DuckDNS endpoint, and split-tunnel AllowedIPs of 192.168.1.0/24, 10.10.0.0/24.
By LK Wood IV · 2026-05-27 · ~11 min read · St. Louis County, MO
Tailscale is easier. If you want the 15-minute path to remote access, the Tailscale tutorial is the right read. WireGuard is for when you want zero coordinator: your server, your key pair, no third-party knowing which clients are connected. (Weighing WireGuard against OpenVPN instead? See the protocol comparison.)
This guide sets up a WireGuard server in a Proxmox LXC container, generates client configs for phones and laptops, and covers the split vs full tunnel decision.
What you’ll have at the end
- WireGuard server running in a Proxmox LXC, listening on UDP port 51820
- Clients (phone, laptop) that can reach your homelab from anywhere
- Your choice of split tunnel (access homelab only) or full tunnel (all traffic through home)
- Dynamic DNS hostname so it works when your home IP changes
Prerequisites
- Proxmox VE 8 host on a home network with internet access
- A port forward on your router: UDP 51820 → your WireGuard LXC IP
- Optionally: a DuckDNS or Cloudflare DNS hostname for your home IP
Verify WireGuard kernel module on the host:
# On the Proxmox host (not inside an LXC)
lsmod | grep wireguard
# Should show: wireguard
# If not, load it:
modprobe wireguard
echo "wireguard" >> /etc/modules
Step 1: Create the LXC container
In Proxmox web UI → Create CT:
Hostname: wireguard
Template: Debian 12 (bookworm)
Storage: 4GB disk
RAM: 256MB
vCPU: 1
Network: Static IP (e.g., 192.168.1.7/24)
Privileged: yes (simplest for net_admin capability)
Start the container, then inside it:
apt update && apt install -y wireguard qrencode
Step 2: Generate server key pair
# Inside the WireGuard LXC
cd /etc/wireguard
umask 077
# Generate server private and public keys
wg genkey | tee server_private.key | wg pubkey > server_public.key
cat server_private.key
cat server_public.key
Keep server_private.key secure — anyone with the private key can decrypt traffic.
Step 3: Create the server config
nano /etc/wireguard/wg0.conf
[Interface]
# The WireGuard server's IP on the VPN subnet
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <paste server_private.key here>
# Enable IP forwarding and NAT for client traffic
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# Clients are added below as [Peer] blocks
The Address = 10.10.0.1/24 line defines the VPN subnet, and every client’s AllowedIPs (your LAN such as 192.168.1.0/24, or 0.0.0.0/0 for full-tunnel) is also a CIDR block. The subnet & CIDR calculator makes it easy to get those masks and host ranges right — and to pick a VPN subnet that won’t overlap the LAN you’re routing to.
The 10.10.0.0/24 subnet is the WireGuard VPN subnet — separate from your home LAN (192.168.1.0/24). The server gets 10.10.0.1; clients get 10.10.0.2, 10.10.0.3, etc.
Enable IP forwarding:
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
Start and enable WireGuard:
systemctl enable --now wg-quick@wg0
# Verify
wg show
Step 4: Generate client configs
For each client (phone, laptop, etc.) generate a key pair and config. Do this on the server for convenience:
# Generate client keys (do this for each client)
wg genkey | tee client1_private.key | wg pubkey > client1_public.key
cat client1_private.key # goes in the client config
cat client1_public.key # goes in the server config as a [Peer]
Client config (save to a file or display as QR code):
[Interface]
Address = 10.10.0.2/32
PrivateKey = <client1_private.key>
DNS = 192.168.1.5 # your AdGuard Home IP, or 1.1.1.1 if not running AdGuard
[Peer]
# The WireGuard server
PublicKey = <server_public.key>
Endpoint = your-home.duckdns.org:51820
# Split tunnel: access homelab only
AllowedIPs = 192.168.1.0/24, 10.10.0.0/24
# Full tunnel: all traffic through home (uncomment instead)
# AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
PersistentKeepalive = 25 keeps the connection alive through NAT — without it, an idle connection behind NAT may drop after a few minutes.
Add the client to the server config:
# Append to /etc/wireguard/wg0.conf on the server
cat >> /etc/wireguard/wg0.conf << EOF
[Peer]
# Client 1 (phone)
PublicKey = <client1_public.key>
AllowedIPs = 10.10.0.2/32
EOF
# Reload WireGuard (no downtime for other clients)
wg syncconf wg0 <(wg-quick strip wg0)
Display the client config as a QR code (scan with the WireGuard app on iOS/Android):
# Create the client config as a file first
cat > /tmp/client1.conf << 'EOF'
[Interface]
Address = 10.10.0.2/32
PrivateKey = <client1_private.key>
DNS = 192.168.1.5
[Peer]
PublicKey = <server_public.key>
Endpoint = your-home.duckdns.org:51820
AllowedIPs = 192.168.1.0/24, 10.10.0.0/24
PersistentKeepalive = 25
EOF
qrencode -t ansiutf8 < /tmp/client1.conf
# Or save as PNG:
qrencode -t PNG -o /tmp/client1.png < /tmp/client1.conf
Delete the client private key file from the server after you’ve scanned it — it should only exist on the client.
Step 5: Set up dynamic DNS
If your home IP changes (most residential ISPs assign dynamic IPs), use a free DDNS service:
DuckDNS (free, simple):
- Go to duckdns.org, create an account, create a domain:
yourname.duckdns.org - Create an update script:
mkdir -p /opt/duckdns
cat > /opt/duckdns/duck.sh << 'EOF'
#!/bin/bash
echo url="https://www.duckdns.org/update?domains=yourname&token=YOUR-TOKEN&ip=" | curl -k -o /opt/duckdns/duck.log -K -
EOF
chmod +x /opt/duckdns/duck.sh
# Add to cron — update every 5 minutes
echo "*/5 * * * * root /opt/duckdns/duck.sh >/dev/null 2>&1" >> /etc/cron.d/duckdns
- Use
yourname.duckdns.org:51820as the Endpoint in all your client configs.
Step 6: Set up the port forward
On your router (OPNsense, pfSense, or consumer firmware):
- Forward UDP port 51820 to your WireGuard LXC IP (
192.168.1.7)
In OPNsense: Firewall → NAT → Port Forward → Add:
- Interface: WAN
- Protocol: UDP
- Destination port: 51820
- Redirect target: 192.168.1.7, port 51820
Verify the connection
On a client, after importing the config:
- Enable the WireGuard tunnel
- Check that you can reach the server:
ping 10.10.0.1 - For split tunnel: verify you can reach homelab devices:
ping 192.168.1.2(Proxmox host) - For full tunnel: verify your exit IP: visit a “what is my IP” site — it should show your home IP
On the server, wg show displays connected peers, their last handshake time, and transfer stats. A handshake within the last 3 minutes means the client is actively connected.
Adding AdGuard Home as VPN DNS
If you’re running AdGuard Home for DNS filtering and local hostname resolution, set it as the DNS in client configs:
[Interface]
DNS = 192.168.1.5 # AdGuard Home IP
This lets VPN clients:
- Resolve
pve.lan,nas.lan, and other local hostnames - Get DNS-level ad blocking while connected to the VPN
- Use AdGuard’s split DNS without a separate Tailscale configuration
Split tunnel vs full tunnel
Split tunnel (AllowedIPs = 192.168.1.0/24, 10.10.0.0/24):
- Only homelab traffic goes through the VPN
- Internet traffic uses the local connection at the client’s location
- Faster for general browsing; no impact on video streaming
- Can’t browse the web through your home IP
Full tunnel (AllowedIPs = 0.0.0.0/0, ::/0):
- All traffic routes through the WireGuard server and your home network
- Use your home IP as the exit node
- Useful on untrusted networks (airports, hotels) or for geo-unlocking
- Your home upload bandwidth becomes the internet speed limit for clients
For a homelab VPN where the goal is remote access to services, split tunnel is usually the right choice — it’s faster and doesn’t load your home upload connection with all internet traffic.
WireGuard vs Tailscale: the honest comparison
| WireGuard (self-hosted) | Tailscale | |
|---|---|---|
| Setup time | 30–60 min | 15 min |
| Third-party dependency | None | Tailscale coordinator |
| Works behind double NAT | Requires port forward on one side | Yes, fully automatic |
| Client count | Unlimited | Generous device allowance, 6 free users |
| Key management | Manual | Automatic |
| ACLs / per-client rules | Manual iptables | Tailscale ACL policy |
| Mobile app | Official WireGuard app | Tailscale app |
| Local DNS integration | Manual (set DNS per client) | MagicDNS, automatic |
Tailscale wins on simplicity and NAT traversal. WireGuard wins on control, privacy (no coordinator logs), and flexibility (full tunnel, custom DNS, any subnet routing). For the full decision framework — including which one to pick behind CGNAT — see Tailscale vs WireGuard: which one should you actually run?.
If you have OPNsense already, it has a built-in WireGuard plugin that eliminates the need for a separate LXC container — it runs directly on the firewall and gets port forwarded automatically.
Running VLANs? See the VLAN homelab guide for segmenting your WireGuard clients from IoT and trusted LAN traffic. For OPNsense specifically, the OPNsense mini PC setup guide covers the WireGuard plugin under Firewall → WireGuard.
Sources
- WireGuard Quick Start – official guide for generating keys, configuring peers, endpoints, and PersistentKeepalive.
- Proxmox VE Linux Container (LXC) – official wiki covering LXC creation, privileged vs unprivileged containers, and networking.
- Tailscale: What is Tailscale? – official overview of the coordination layer and WireGuard-based mesh, supporting the comparison section.
- OPNsense WireGuard Road Warrior Setup – official documentation for the built-in WireGuard instance and client peers on the firewall.
- DuckDNS Install – official setup page for the free dynamic DNS service used for the home endpoint.
Frequently asked questions
WireGuard vs Tailscale: which should I use?
Do I need a static IP for a WireGuard server?
Can I run WireGuard in a Proxmox LXC container?
How do I route all client traffic through the WireGuard server (full tunnel)?
How many clients can a WireGuard server handle?
Evidence ledger
- Last updated
- Methodology
- This tutorial was written and edited by Lowell K. Wood IV in St. Louis County, MO. Specs, prices, commands, and version numbers are drawn from the official vendor, reseller, and project documentation current on the date above, and were verified before publishing. First-person hardware claims appear only where the article shows a verifiable artifact — a photo, receipt, or measurement — or links to the TechFuelHQ Open Bench Datasets. Every fact is human-verified against its cited source before publishing; AI assists with first-draft structure and source-gathering, not with the verdict. Full editorial standard: methodology.
- Update log
- 2026-07-25 — Last reviewed and updated.
- Corrections
- Spotted an error or stale price? Email hello@techfuelhq.com. Confirmed corrections are added to the update log above.