WireGuard VPN¶
Deploy a WireGuard VPN server using the wireguard module.
Overview¶
This example demonstrates:
- Using
fscm.modules.wireguardfor VPN configuration - Key generation workflow
- Multi-peer configuration
- iptables integration for VPN routing
Architecture¶
Internet
│
┌───────┴───────┐
│ VPN Server │
│ 203.0.113.1 │
│ (wg0) │
│ 10.100.0.1/24 │
└───────┬───────┘
│
┌───────────────┼───────────────┐
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ Laptop │ │ Phone │ │ Tablet │
│10.100.0.2 │ │10.100.0.3 │ │10.100.0.4 │
└───────────┘ └───────────┘ └───────────┘
Files¶
Configuration¶
# Server configuration
VPN_INTERFACE = "wg0"
VPN_PORT = 51820
VPN_NETWORK = "10.100.0.0/24"
VPN_SERVER_IP = "10.100.0.1"
PUBLIC_ENDPOINT = "vpn.example.com" # Or public IP
# Peer definitions
PEERS = [
{"name": "laptop", "ip": "10.100.0.2"},
{"name": "phone", "ip": "10.100.0.3"},
{"name": "tablet", "ip": "10.100.0.4"},
]
Usage¶
# Preview changes
python examples/wireguard_vpn/deploy.py --dry-run
# Deploy
sudo python examples/wireguard_vpn/deploy.py
# Client configs are saved to /etc/wireguard/clients/
What Gets Deployed¶
1. WireGuard Installation¶
2. Key Generation¶
def generate_keypair():
"""Generate a WireGuard keypair."""
private_key = getstdout("wg genkey").strip()
public_key = getstdout(f"echo '{private_key}' | wg pubkey").strip()
return private_key, public_key
3. Server Configuration¶
/etc/wireguard/wg0.conf:
[Interface]
Address = 10.100.0.1/24
ListenPort = 51820
PrivateKey = <server_private_key>
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]
# laptop
PublicKey = <laptop_public_key>
AllowedIPs = 10.100.0.2/32
[Peer]
# phone
PublicKey = <phone_public_key>
AllowedIPs = 10.100.0.3/32
[Peer]
# tablet
PublicKey = <tablet_public_key>
AllowedIPs = 10.100.0.4/32
4. Client Configurations¶
/etc/wireguard/clients/laptop.conf:
[Interface]
PrivateKey = <laptop_private_key>
Address = 10.100.0.2/32
DNS = 1.1.1.1
[Peer]
PublicKey = <server_public_key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
5. IP Forwarding¶
def enable_ip_forwarding():
lineinfile(
"/etc/sysctl.conf",
line="net.ipv4.ip_forward=1",
regexp=r"^#?net\.ipv4\.ip_forward"
)
run("sysctl -p", sudo=True)
6. Firewall Rules¶
def configure_firewall():
# Allow WireGuard port
run(f"ufw allow {VPN_PORT}/udp", sudo=True)
# Or with iptables
run(f"iptables -A INPUT -p udp --dport {VPN_PORT} -j ACCEPT", sudo=True)
Key Code Sections¶
Using wireguard Module¶
from fscm.modules.wireguard import Server, Peer, server
def setup_vpn():
# Generate server keys
srv_private, srv_public = generate_keypair()
# Create server config
srv = Server(
address=f"{VPN_SERVER_IP}/24",
listen_port=VPN_PORT,
private_key=srv_private,
public_key=srv_public,
post_up="iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE",
post_down="iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE"
)
# Create peers
peers = []
for peer_def in PEERS:
peer_private, peer_public = generate_keypair()
peers.append(Peer(
name=peer_def["name"],
address=f"{peer_def['ip']}/32",
private_key=peer_private,
public_key=peer_public,
allowed_ips="0.0.0.0/0"
))
# Generate all configs
server(srv, peers, endpoint=f"{PUBLIC_ENDPOINT}:{VPN_PORT}")
Enable and Start¶
def start_wireguard():
run("systemctl enable wg-quick@wg0", sudo=True)
run("systemctl start wg-quick@wg0", sudo=True)
Client Setup¶
Linux¶
# Copy client config
scp user@vpn.example.com:/etc/wireguard/clients/laptop.conf /etc/wireguard/
# Start VPN
sudo wg-quick up laptop
macOS / iOS / Android¶
- Install WireGuard app
- Import configuration file or scan QR code
Generate QR Code¶
Adding New Peers¶
def add_peer(name: str, ip: str):
"""Add a new peer to existing VPN."""
# Generate keys
private, public = generate_keypair()
# Add to server config
peer_section = f"""
[Peer]
# {name}
PublicKey = {public}
AllowedIPs = {ip}/32
"""
run(f"echo '{peer_section}' >> /etc/wireguard/wg0.conf", sudo=True)
# Reload without dropping connections
run("wg syncconf wg0 <(wg-quick strip wg0)", sudo=True)
# Generate client config
generate_client_config(name, ip, private)
Troubleshooting¶
Check Interface Status¶
View Connection Logs¶
Test Connectivity¶
Common Issues¶
| Issue | Solution |
|---|---|
| Can't connect | Check firewall allows UDP 51820 |
| No internet through VPN | Check NAT/masquerade rules |
| Handshake timeout | Verify endpoint is reachable |
| DNS not working | Check DNS in client config |