WireGuard Denver Tunnel¶
Overview¶
WireGuard VPN tunnel through rocky (Meanservers, Denver) to appear as if located in Denver, Colorado.
| Component | Value |
|---|---|
| Server | rocky (193.8.172.100) |
| Exit Location | Greenwood Village, CO |
| Tunnel Network | 10.99.0.0/24 |
| Port | 51820/UDP |
| Protocol | WireGuard |
Architecture¶
┌─────────┐ WireGuard ┌─────────┐
│ luna │◄─────────────────────────►│ rocky │──► Internet
│10.99.0.2│ 10.99.0.0/24 │10.99.0.1│ (Denver IP)
└─────────┘ └─────────┘
│ │
│ Starlink │ Meanservers
│ (Colorado) │ (Denver)
└──────────────────────────────────────┘
Clients¶
| Client | Tunnel IP | Config Location | Status |
|---|---|---|---|
| luna | 10.99.0.2 | ~/.wireguard/rocky-denver.conf |
✅ Active |
| owl (VLAN) | TBD | OPNsense WireGuard | 🔜 Planned |
Usage (luna)¶
Shell functions are defined in ~/.zshrc:
Manual Commands¶
# Bring tunnel up (sudo env injects homebrew bash 5+ into PATH for wg-quick's shebang)
sudo env PATH="/opt/homebrew/bin:$PATH" wg-quick up ~/.wireguard/rocky-denver.conf
# Bring tunnel down
sudo env PATH="/opt/homebrew/bin:$PATH" wg-quick down ~/.wireguard/rocky-denver.conf
# Check WireGuard status
sudo wg show
# Verify Denver IP
curl https://ipinfo.io
Server Configuration (rocky)¶
Config file: /etc/wireguard/wg0.conf
[Interface]
Address = 10.99.0.1/24
ListenPort = 51820
PrivateKey = <from 1Password: wireguard_rocky_denver_server, vault: scandora-automation>
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
[Peer]
# luna
PublicKey = z2IPPElnNhvnBXH0GzYZrtPAUMWv+78xVtidfxYIEXs=
AllowedIPs = 10.99.0.2/32
System configuration:
- IP forwarding:
net.ipv4.ip_forward=1in/etc/sysctl.d/99-wireguard.conf - Firewall:
ufw allow 51820/udp - Service:
systemctl enable wg-quick@wg0
Client Configuration (luna)¶
Config file: ~/.wireguard/rocky-denver.conf
[Interface]
Address = 10.99.0.2/24
PrivateKey = <from 1Password: wireguard_luna_denver_client, vault: scandora-automation>
# macOS wg-quick bug 1: route -n get falsely skips /3 and /4 AllowedIPs entries.
PostUp = /sbin/route -q -n add -inet 16.0.0.0/4 -interface %i
PostUp = /sbin/route -q -n add -inet 32.0.0.0/3 -interface %i
PostUp = /sbin/route -q -n add -inet 64.0.0.0/3 -interface %i
PostUp = /sbin/route -q -n add -inet 112.0.0.0/4 -interface %i
PostUp = /sbin/route -q -n add -inet 128.0.0.0/3 -interface %i
PostUp = /sbin/route -q -n add -inet 176.0.0.0/4 -interface %i
PostUp = /sbin/route -q -n add -inet 208.0.0.0/4 -interface %i
PostUp = /sbin/route -q -n add -inet 224.0.0.0/3 -interface %i
# macOS wg-quick bug 2: split AllowedIPs mode skips endpoint exemption route,
# causing a routing loop. Add host route for endpoint via current default gateway.
# NOTE: /usr/sbin/netstat (full path) is required — sudo strips PATH so bare
# 'netstat' silently fails, leaving no exemption route and causing a routing loop.
PostUp = /sbin/route -q -n add -host 193.8.172.100 $(/usr/sbin/netstat -rn -f inet | awk '/^default/{print $2; exit}')
PostDown = /sbin/route -q -n delete -host 193.8.172.100
[Peer]
PublicKey = Y2G2hNJNj0XckPdVuxDMRYoEZpV97wAMcnGRAPE710w=
Endpoint = 193.8.172.100:51820
# Routes all public internet through rocky; excludes RFC1918 (10/8, 172.16/12,
# 192.168/16) and RFC6598 CGNAT (100.64/10, Starlink) so all private networks
# remain reachable at any site. wg-quick's endpoint exemption handled via PostUp.
AllowedIPs = 0.0.0.0/5, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/3, 96.0.0.0/6, 100.0.0.0/10, 100.128.0.0/9, 101.0.0.0/8, 102.0.0.0/7, 104.0.0.0/5, 112.0.0.0/4, 128.0.0.0/3, 160.0.0.0/5, 168.0.0.0/6, 172.0.0.0/12, 172.32.0.0/11, 172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, 176.0.0.0/4, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 224.0.0.0/3
PersistentKeepalive = 25
Notes:
- All public internet routes through rocky; RFC1918 and CGNAT (Starlink 100.64/10) stay local
- Works at any site (Owl, Blue, remote) — no hardcoded gateway in config
- Two macOS wg-quick bugs require PostUp workarounds (see comments in config above)
- To regenerate the AllowedIPs list:
python3 scripts/testing/wireguard-allowedips-calc.py
Key Management¶
Keys are stored in 1Password:
| Item | Vault | Contains |
|---|---|---|
| wireguard_rocky_denver_server | scandora-automation | Server public/private keys |
| wireguard_luna_denver_client | scandora-automation | Client public/private keys |
Adding New Clients¶
- Generate keypair on client:
- Add peer to rocky's
/etc/wireguard/wg0.conf:
- Reload rocky's config:
- Create client config with:
- Tunnel IP: 10.99.0.X/24
- Server public key:
Y2G2hNJNj0XckPdVuxDMRYoEZpV97wAMcnGRAPE710w= - Endpoint:
193.8.172.100:51820
IP Allocation¶
| IP | Client | Notes |
|---|---|---|
| 10.99.0.1 | rocky | Server |
| 10.99.0.2 | luna | Workstation |
| 10.99.0.3 | (reserved) | owl VLAN gateway |
| 10.99.0.10-99 | (reserved) | owl VLAN clients |
Troubleshooting¶
Tunnel up but no connectivity¶
- Check if handshake completed:
Look for "latest handshake" - if missing, firewall may be blocking.
- Check IP forwarding on server:
Should return 1.
- Check NAT rules:
macOS wg-quick bash version error¶
macOS ships with bash 3.2, but wg-quick requires bash 4+. Use sudo env to inject
Homebrew's bash 5 into PATH — wg-quick's #!/usr/bin/env bash shebang resolves it:
Why not sudo /opt/homebrew/bin/bash $(which wg-quick)?
PostUp commands inherit the environment from wg-quick, which still runs with sudo's
stripped PATH. This causes bare commands like netstat in PostUp to silently fail.
Using sudo env PATH=... ensures all subprocesses (including PostUp) see the full PATH.
Future: OPNsense VLAN (owl-den01)¶
When in Iowa, configure:
- WireGuard interface on OPNsense
- VLAN
owl-den01for Denver exit traffic - Policy routing to send VLAN traffic through WireGuard
- Any device on the VLAN appears in Denver