Traditional WireGuard configuration requires modifying /etc/wireguard/wg0.conf
followed by a service restart (wg-quick down wg0 && wg-quick up wg0
), which causes:
- 1-3 second connectivity interruption for existing peers
- Mandatory re-handshake for all connected clients
- Session termination for UDP stateful connections
The wg
utility provides runtime configuration without config file changes:
# Add new peer dynamically
wg set wg0 peer [PUBLIC_KEY] allowed-ips [IP_RANGE]
# Remove peer
wg set wg0 peer [PUBLIC_KEY] remove
# Persist changes (optional)
wg-quick save wg0
Here's a Python script using the subprocess
module:
import subprocess
def add_peer(interface, pubkey, ip):
cmd = f"wg set {interface} peer {pubkey} allowed-ips {ip}"
subprocess.run(cmd.split(), check=True)
def remove_peer(interface, pubkey):
cmd = f"wg set {interface} peer {pubkey} remove"
subprocess.run(cmd.split(), check=True)
# Example usage:
add_peer("wg0", "ODUxMjQ0YmQtY2UwNC00NjA4LTg0M2YtYjBjYzYyMWI1YWY=", "10.0.0.3/32")
For zero-downtime key rotation:
# Add new key first
wg set wg0 peer [NEW_PUBKEY] allowed-ips [IP]
# Then remove old key after confirmation
wg set wg0 peer [OLD_PUBKEY] remove
Ansible playbook example:
- name: Add WireGuard peer dynamically
hosts: vpn_servers
tasks:
- name: Add new peer
command: "wg set wg0 peer {{ item.pubkey }} allowed-ips {{ item.ip }}"
loop: "{{ new_peers }}"
register: wg_result
- name: Save configuration
command: "wg-quick save wg0"
when: wg_result is changed
- Runtime changes aren't persistent across reboots (use
wg-quick save
) - Pre-shared keys must be set during initial interface creation
- Endpoint changes still require client reconnection
- Monitor connection counts with
wg show
WireGuard's design emphasizes simplicity and security, but its configuration model traditionally requires a service restart when modifying peers. This becomes problematic in production environments where:
- Existing connections shouldn't be interrupted
- VPN uptime is critical for business operations
- Frequent peer changes occur in dynamic infrastructures
Standard configuration changes through wg-quick
or manual wg
commands typically require interface restart:
# Traditional approach (disruptive)
sudo wg-quick down wg0
sudo wg-quick up wg0
WireGuard's kernel module actually supports dynamic peer modifications through its netlink interface. Here's how to leverage it:
# Add new peer without restart
sudo wg set wg0 peer PUBKEY allowed-ips 10.0.0.2/32
# Remove peer safely
sudo wg set wg0 peer PUBKEY remove
Here's a Python script that manages peers dynamically while preserving existing connections:
import subprocess
import json
def add_peer(interface, pubkey, allowed_ips):
cmd = f"wg set {interface} peer {pubkey} allowed-ips {allowed_ips}"
subprocess.run(cmd.split(), check=True)
# Persist configuration
with open(f"/etc/wireguard/{interface}.conf", "a") as f:
f.write(f"\n[Peer]\nPublicKey = {pubkey}\nAllowedIPs = {allowed_ips}\n")
# Usage example
add_peer("wg0", "ABC123...XYZ=", "10.0.0.3/32")
When implementing dynamic peer management:
- Configuration Sync: Always update the config file after runtime changes
- Key Rotation: Implement proper key management for security
- Monitoring: Watch for kernel module memory leaks with many peer changes
For high-availability setups, implement dual peers during rotation:
# Add new peer before removing old one
sudo wg set wg0 peer NEW_PUBKEY allowed-ips 10.0.0.2/32
# (Wait for handshake)
sudo wg set wg0 peer OLD_PUBKEY remove