Skip to content

WireGuard

Overview

WireGuard is a modern, high-performance VPN protocol built into the Linux kernel. The solti-ensemble WireGuard role automates client configuration for secure remote connectivity.

Purpose: - Secure remote access to monitoring infrastructure - Encrypted data transport for metrics and logs - NAT traversal for hosts behind firewalls - Low-overhead VPN connectivity

Note: This role configures WireGuard clients that connect to existing WireGuard servers.

Key Features

Security

  • Secure key generation (private/public key pairs)
  • Pre-shared key support for additional security
  • Automatic key backup
  • Secure file permissions (600 for private keys)

Configuration

  • Simple client setup
  • Persistent connection mode
  • Automatic route management
  • DNS configuration support

Lifecycle Management

  • Clean installation (state: present)
  • Complete removal (state: absent)
  • Configuration backup and restoration
  • Idempotent operations

Installation

Basic Client Configuration

- hosts: remote_hosts
  become: true
  roles:
    - role: jackaltx.solti_ensemble.wireguard
      vars:
        wireguard_state: present
        wireguard_endpoint: "hub.example.com:51820"
        wireguard_server_public_key: "{{ vault_wg_server_pubkey }}"
        wireguard_client_address: "10.10.0.20/24"
        wireguard_allowed_ips: "10.10.0.0/24"

Client with Pre-Shared Key

- hosts: remote_hosts
  become: true
  roles:
    - role: jackaltx.solti_ensemble.wireguard
      vars:
        wireguard_endpoint: "hub.example.com:51820"
        wireguard_server_public_key: "{{ vault_wg_server_pubkey }}"
        wireguard_preshared_key: "{{ vault_wg_psk }}"
        wireguard_client_address: "10.10.0.20/24"
        wireguard_allowed_ips: "10.10.0.0/24"

Configuration Options

Required Variables

# WireGuard server endpoint
wireguard_endpoint: "hub.example.com:51820"

# Server's public key
wireguard_server_public_key: ""

# Client's VPN IP address
wireguard_client_address: "10.10.0.20/24"

Optional Variables

# State management
wireguard_state: present           # 'present' to install, 'absent' to remove

# Network configuration
wireguard_allowed_ips: "10.10.0.0/24"  # Routes through VPN
wireguard_dns: "10.10.0.1"              # DNS server via VPN
wireguard_persistent_keepalive: 25      # Keep connection alive (NAT traversal)

# Security
wireguard_preshared_key: ""        # Additional encryption layer

# Interface
wireguard_interface: "wg0"         # Interface name

# Backup
wireguard_backup_enabled: true
wireguard_backup_dir: "/root/wireguard-backup"

Use Case: Remote Monitoring

Architecture

Remote Host (ispconfig3-server.example.com)
  ├─ WireGuard Client (10.10.0.20)
  ├─ Telegraf → sends to 10.10.0.11:8086
  └─ Alloy → sends to 10.10.0.11:3100
           ↓ [WireGuard Tunnel]
Monitoring Hub (monitor11.example.com)
  ├─ WireGuard Server (10.10.0.11)
  ├─ InfluxDB (listens on 10.10.0.11:8086)
  └─ Loki (listens on 10.10.0.11:3100)

Deployment

Step 1: Configure WireGuard on monitoring hub

(Server setup not covered by this role - use manual configuration or separate role)

# On hub: Generate server keys
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key

# On hub: Create server config
cat > /etc/wireguard/wg0.conf << EOF
[Interface]
PrivateKey = $(cat /etc/wireguard/server_private.key)
Address = 10.10.0.11/24
ListenPort = 51820

[Peer]
# Client: ispconfig3-server.example.com
PublicKey = CLIENT_PUBLIC_KEY_HERE
AllowedIPs = 10.10.0.20/32
EOF

# Start server
systemctl enable --now wg-quick@wg0

Step 2: Deploy WireGuard client on remote host

- hosts: ispconfig3-server.example.com
  become: true
  roles:
    - role: jackaltx.solti_ensemble.wireguard
      vars:
        wireguard_endpoint: "monitor11.example.com:51820"
        wireguard_server_public_key: "{{ vault_wg_server_pubkey }}"
        wireguard_client_address: "10.10.0.20/24"
        wireguard_allowed_ips: "10.10.0.0/24"
        wireguard_persistent_keepalive: 25

Step 3: Configure monitoring collectors

- hosts: ispconfig3-server.example.com
  roles:
    - role: jackaltx.solti_monitoring.telegraf
      vars:
        telegraf_outputs_influxdb_url: "http://10.10.0.11:8086"

    - role: jackaltx.solti_monitoring.alloy
      vars:
        alloy_loki_endpoint: "http://10.10.0.11:3100"

Service Management

Check Status

systemctl status wg-quick@wg0

Start/Stop/Restart

systemctl start wg-quick@wg0
systemctl stop wg-quick@wg0
systemctl restart wg-quick@wg0

View Connection Status

wg show

Output:

interface: wg0
  public key: CLIENT_PUBLIC_KEY
  private key: (hidden)
  listening port: 51820

peer: SERVER_PUBLIC_KEY
  endpoint: 1.2.3.4:51820
  allowed ips: 10.10.0.0/24
  latest handshake: 45 seconds ago
  transfer: 1.25 MiB received, 856.32 KiB sent
  persistent keepalive: every 25 seconds

Check Connectivity

# Ping VPN gateway
ping -c 3 10.10.0.11

# Test monitoring endpoint
curl -I http://10.10.0.11:8086/health  # InfluxDB
curl -s http://10.10.0.11:3100/ready   # Loki

Key Management

Client Keys

The role automatically generates client keys if they don't exist:

# Private key (600 permissions)
/etc/wireguard/privatekey

# Public key (644 permissions)
/etc/wireguard/publickey

Backup Keys

Keys are backed up to configurable location:

# Default backup location
/root/wireguard-backup/wg0-YYYYMMDD-HHMMSS.conf

Retrieve Client Public Key

After role execution, retrieve the public key:

# Method 1: From file
cat /etc/wireguard/publickey

# Method 2: From running interface
wg show wg0 public-key

Add this key to server's [Peer] section.

Network Configuration

AllowedIPs Patterns

Route only VPN network:

wireguard_allowed_ips: "10.10.0.0/24"

Route all traffic through VPN:

wireguard_allowed_ips: "0.0.0.0/0"

Route multiple networks:

wireguard_allowed_ips: "10.10.0.0/24, 192.168.1.0/24"

Persistent Keepalive

Why needed: Maintains connection through NAT/firewall

When to use: - Client behind NAT/firewall - Monitoring with continuous data flow - Prevent connection timeouts

Configuration:

wireguard_persistent_keepalive: 25  # Send keepalive every 25 seconds

Disable if not needed (server-side connections):

wireguard_persistent_keepalive: 0

Firewall Configuration

Client Firewall (if using ufw)

# Allow WireGuard UDP traffic
ufw allow 51820/udp

# Allow outbound to VPN network
ufw allow out to 10.10.0.0/24

Server Firewall (hub side)

# Rocky Linux
firewall-cmd --add-port=51820/udp --permanent
firewall-cmd --reload

# Debian/Ubuntu
ufw allow 51820/udp

Troubleshooting

Connection Not Establishing

Check service status:

systemctl status wg-quick@wg0
journalctl -u wg-quick@wg0 -f

Check configuration:

cat /etc/wireguard/wg0.conf

Verify keys:

# Client public key
cat /etc/wireguard/publickey

# Server public key (must match config)
grep PublicKey /etc/wireguard/wg0.conf

Test endpoint reachability:

# Test UDP port
nc -vzu hub.example.com 51820

No Handshake

Symptom: wg show displays no handshake or very old timestamp

Causes: - Firewall blocking UDP port 51820 - Incorrect endpoint address - Key mismatch - Server not running

Debug:

# Enable WireGuard debug logging
echo module wireguard +p > /sys/kernel/debug/dynamic_debug/control
journalctl -kf | grep wireguard

Can Ping VPN but Not Services

Check routing:

ip route show

Should see route via wg0:

10.10.0.0/24 dev wg0 scope link

Check services listening on VPN interface:

ss -tulpn | grep 10.10.0.11

High CPU Usage

Possible causes: - Frequent keepalives (increase interval) - Large data transfers - Encryption overhead

Monitor:

top -p $(pgrep wg)

Platform-Specific Notes

Debian 12

Package: wireguard

Module: Kernel module (mainline kernel ≥5.6)

Config: /etc/wireguard/wg0.conf

Rocky Linux 9

Package: wireguard-tools

Module: Kernel module (included in kernel)

Config: /etc/wireguard/wg0.conf

SELinux: No special configuration needed

Ubuntu 24.04

Package: wireguard

Module: Kernel module (included)

Config: /etc/wireguard/wg0.conf

Removal

Remove WireGuard (Keep Config)

- hosts: remote_hosts
  become: true
  roles:
    - role: jackaltx.solti_ensemble.wireguard
      vars:
        wireguard_state: absent
        wireguard_remove_config: false

Actions: - Stop wg-quick@wg0 service - Disable from boot - Remove packages - Keep /etc/wireguard/ directory

Complete Removal

- hosts: remote_hosts
  become: true
  roles:
    - role: jackaltx.solti_ensemble.wireguard
      vars:
        wireguard_state: absent
        wireguard_remove_config: true

Actions: - Stop and disable service - Remove packages - Delete /etc/wireguard/ directory - Delete backup directory

Security Best Practices

  1. Store Keys in Ansible Vault
# vars/vault.yml (encrypted)
vault_wg_server_pubkey: "SERVER_PUBLIC_KEY"
vault_wg_psk: "PRE_SHARED_KEY"
  1. Use Pre-Shared Keys

Adds quantum-resistant layer:

wireguard_preshared_key: "{{ vault_wg_psk }}"
  1. Limit AllowedIPs

Route only necessary networks:

wireguard_allowed_ips: "10.10.0.0/24"  # VPN network only
  1. Backup Keys Securely
# Encrypt backups
tar czf - /root/wireguard-backup/ | gpg -e > wg-backup.tar.gz.gpg
  1. Monitor Connection Status
# Alert if no recent handshake
wg show wg0 latest-handshake | awk '{if (systime() - $2 > 300) print "WireGuard connection stale"}'
  1. Rotate Keys Periodically

Plan for key rotation (manual or automated):

# Generate new keys
wg genkey | tee /etc/wireguard/privatekey.new | wg pubkey > /etc/wireguard/publickey.new

Integration with solti-monitoring

Monitoring Architecture

# Deploy WireGuard + Monitoring stack
- hosts: remote_hosts
  roles:
    # 1. Establish VPN
    - role: jackaltx.solti_ensemble.wireguard
      vars:
        wireguard_endpoint: "hub.example.com:51820"
        wireguard_server_public_key: "{{ vault_wg_server_pubkey }}"
        wireguard_client_address: "10.10.0.20/24"
        wireguard_allowed_ips: "10.10.0.0/24"

    # 2. Configure collectors
    - role: jackaltx.solti_monitoring.telegraf
      vars:
        telegraf_outputs_influxdb_url: "http://10.10.0.11:8086"

    - role: jackaltx.solti_monitoring.alloy
      vars:
        alloy_loki_endpoint: "http://10.10.0.11:3100"

Reference Deployment

ispconfig3-server.example.com (Linode VPS): - WireGuard client connected to monitor11 - VPN address: 10.10.0.20 - Routes monitoring traffic through VPN - Persistent keepalive: 25 seconds (NAT traversal) - Encrypted metrics and logs to hub

Resource Requirements

Client Resources

  • CPU: Negligible (<1% for typical monitoring traffic)
  • RAM: <100MB
  • Disk: <10MB
  • Network: Low overhead (~60 bytes per packet)

Performance

Throughput: Up to 1+ Gbps (depending on hardware)

Latency: +1-2ms vs unencrypted

CPU Usage: Minimal (kernel-space encryption)

Next Steps

  • Monitoring Integration - Configure Telegraf and Alloy
  • Security Hardening - Add fail2ban rules for WireGuard
  • Multi-Site Deployment - Connect multiple remote hosts
  • Server Configuration - Set up WireGuard hub (manual or separate role)