Wireguard-based VPN mesh network with automatic IPv6 address allocation
<div style="background-color: #77DD77; color: white; padding: 10px; border-radius: 20px; text-align: center;">
Network
</div>This service provides a WireGuard-based VPN mesh network with automatic IPv6 address allocation and routing between clan machines.
The WireGuard service creates a secure mesh network between clan machines using two roles:
/40 ULA prefix (deterministically generated from instance name)/56 subnet from the base /40:8750:a09b:0:1)/56 prefix to create unique addresses: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/96 subnet for routing flexibility# In your clan.nix
{
instances = {
wireguard = {
module.name = "wireguard";
module.input = "clan-core";
roles.controller = {
machines.server1 = {};
settings = {
# Public endpoint where this controller can be reached
endpoint = "vpn.example.com";
# Optional: Change the UDP port (default: 51820)
port = 51820;
};
};
roles.peer = {
# No configuration needed if only one controller exists
machines.laptop1 = {};
};
};
}
} {
instances = {
wireguard = {
module.name = "wireguard";
module.input = "clan-core";
roles.controller.machines = {
server1.settings.endpoint = "vpn1.example.com";
server2.settings.endpoint = "vpn2.example.com";
server3.settings.endpoint = "vpn3.example.com";
};
roles.peer.machines.laptop1 = {
# Must specify which controller subnet is exposed as the default in /etc/hosts, when multiple controllers exist
settings.controller = "server1";
};
};
}
} 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 addresslaptop1.vpn - resolves to laptop1's IPv6 addressThis allows machines to communicate using hostnames instead of IPv6 addresses:
# Ping another machine by hostname
ping6 server1.vpn
# SSH to another machine
ssh user@laptop1.vpn sudo wg show ip addr show dev <instance-name> ip -6 route show dev <instance-name> If you see this error in your logs:
wireguard: Could not bring up interface, ignoring: Address already in use This means the configured port (default: 51820) is already in use by another service or WireGuard instance. Solutions:
Check for conflicting WireGuard instances:
sudo wg show
sudo ss -ulnp | grep 51820Use a different port:
services.wireguard.myinstance = {
roles.controller = {
endpoint = "vpn.example.com";
port = 51821; # 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.
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> The wireguard service has the following roles:
controller roleDomain suffix to use for hostnames in /etc/hosts. Defaults to the instance name.
Type: null or string
Default:
instanceName Declared in: clanServices/wireguard/default.nix
Endpoint where the controller can be reached
Type: string
"vpn.clan.lol"Declared in: clanServices/wireguard/default.nix
Port for the wireguard interface
Type: signed integer
Default:
51820 51820Declared in: clanServices/wireguard/default.nix
peer roleMachinename of the controller to attach to
Type: string
"controller1"Declared in: clanServices/wireguard/default.nix
Domain suffix to use for hostnames in /etc/hosts. Defaults to the instance name.
Type: null or string
Default:
instanceName Declared in: clanServices/wireguard/default.nix
Port for the wireguard interface
Type: signed integer
Default:
51820 51820Declared in: clanServices/wireguard/default.nix