wireguard
Wireguard-based VPN mesh network with automatic IPv6 address allocation
Wireguard VPN Service
This service provides a Wireguard-based VPN mesh network with automatic IPv6 address allocation and routing between clan machines.
Overview
The wireguard service creates a secure mesh network between clan machines using two roles: - Controllers: Machines with public endpoints that act as connection points and routers - Peers: Machines that connect through controllers to access the network
Requirements
- Controllers must have a publicly accessible endpoint (domain name or static IP)
- Peers must be in networks where UDP traffic is not blocked (uses port 51820 by default, configurable)
Features
- Automatic IPv6 address allocation using ULA (Unique Local Address) prefixes
- Full mesh connectivity between all machines
- Automatic key generation and distribution
- IPv6 forwarding on controllers for inter-peer communication
- Support for multiple controllers for redundancy
Network Architecture
IPv6 Address Allocation
- Base network:
/40
ULA prefix (deterministically generated from instance name) - Controllers: Each gets a
/56
subnet from the base/40
- Peers: Each gets a unique 64-bit host suffix that is used in ALL controller subnets
Addressing Design
- Each peer generates a unique host suffix (e.g.,
:8750:a09b:0:1
) - This suffix is appended to each controller's
/56
prefix to create unique addresses - Example: peer1 with suffix
:8750:a09b:0:1
gets: fd51:19c1:3b:f700:8750:a09b:0:1
in controller1's subnetfd51:19c1:c1:aa00:8750:a09b:0:1
in controller2's subnet- Controllers allow each peer's
/96
subnet for routing flexibility
Connectivity
- Peers use a single WireGuard interface with multiple IPs (one per controller subnet)
- Controllers connect to ALL other controllers and ALL peers on a single interface
- Controllers have IPv6 forwarding enabled to route traffic between peers
- All traffic between peers flows through controllers
- Symmetric routing is maintained as each peer has consistent IPs across all controllers
Example Network Topology
graph TB
subgraph Controllers
C1[controller1<br/>endpoint: vpn1.example.com<br/>fd51:19c1:3b:f700::/56]
C2[controller2<br/>endpoint: vpn2.example.com<br/>fd51:19c1:c1:aa00::/56]
end
subgraph Peers
P1[peer1<br/>designated: controller1]
P2[peer2<br/>designated: controller2]
P3[peer3<br/>designated: controller1]
end
%% Controllers connect to each other
C1 <--> C2
%% All peers connect to all controllers
P1 <--> C1
P1 <--> C2
P2 <--> C1
P2 <--> C2
P3 <--> C1
P3 <--> C2
%% Peer-to-peer traffic flows through controllers
P1 -.->|via controllers| P3
P1 -.->|via controllers| P2
P2 -.->|via controllers| P3
classDef controller fill:#f9f,stroke:#333,stroke-width:4px
classDef peer fill:#bbf,stroke:#333,stroke-width:2px
class C1,C2 controller
class P1,P2,P3 peer
Configuration
Basic Setup with Single Controller
# In your flake.nix or inventory
{
services.wireguard.server1 = {
roles.controller = {
# Public endpoint where this controller can be reached
endpoint = "vpn.example.com";
# Optional: Change the UDP port (default: 51820)
port = 51820;
};
};
services.wireguard.laptop1 = {
roles.peer = {
# No configuration needed if only one controller exists
};
};
}
Multiple Controllers Setup
{
services.wireguard.server1 = {
roles.controller = {
endpoint = "vpn1.example.com";
};
};
services.wireguard.server2 = {
roles.controller = {
endpoint = "vpn2.example.com";
};
};
services.wireguard.laptop1 = {
roles.peer = {
# Must specify which controller subnet is exposed as the default in /etc/hosts, when multiple controllers exist
controller = "server1";
};
};
}
Advanced Options
Automatic Hostname Resolution
The wireguard service automatically adds entries to /etc/hosts
for all machines in the network. Each machine is accessible via its hostname in the format <machine-name>.<instance-name>
.
For example, with an instance named vpn
:
- server1.vpn
- resolves to server1's IPv6 address
- laptop1.vpn
- resolves to laptop1's IPv6 address
This allows machines to communicate using hostnames instead of IPv6 addresses:
Troubleshooting
Check Wireguard Status
Verify IP Addresses
Check Routing
Interface Fails to Start: "Address already in use"
If you see this error in your logs:
This means the configured port (default: 51820) is already in use by another service or wireguard instance. Solutions:
-
Check for conflicting wireguard instances:
-
Use a different port:
-
Ensure unique ports across multiple instances: If you have multiple wireguard instances on the same machine, each must use a different port.
Key Management
Keys are automatically generated and stored in the clan vars system. To regenerate keys:
# Regenerate keys for a specific machine and instance
clan vars generate --service wireguard-keys-<instance-name> --regenerate --machine <machine-name>
# Apply the new keys
clan machines update <machine-name>
Security Considerations
- All traffic is encrypted using Wireguard's modern cryptography
- Private keys never leave the machines they're generated on
- Public keys are distributed through the clan vars system
- Controllers must have publicly accessible endpoints
- Firewall rules are automatically configured for the Wireguard ports
Roles
The wireguard module has the following roles:
- controller
- peer
Options for the controller
role
domain
Domain suffix to use for hostnames in /etc/hosts. Defaults to the instance name.
Type: null or string
Default:
Declared in: clanServices/wireguard/default.nix
endpoint
Endpoint where the controller can be reached
Type: string
Declared in: clanServices/wireguard/default.nix
port
Port for the wireguard interface
Type: signed integer
Default:
Declared in: clanServices/wireguard/default.nix
Options for the peer
role
controller
Machinename of the controller to attach to
Type: string
Declared in: clanServices/wireguard/default.nix
domain
Domain suffix to use for hostnames in /etc/hosts. Defaults to the instance name.
Type: null or string
Default:
Declared in: clanServices/wireguard/default.nix
port
Port for the wireguard interface
Type: signed integer
Default:
Declared in: clanServices/wireguard/default.nix