nix/modules/vpn/wireguard.nix
2026-02-18 23:04:21 +01:00

118 lines
3 KiB
Nix

# NOTE: After deploy, get public key with: `sudo sh -c 'wg pubkey < /etc/wireguard/private.key'`
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.services.wireguard-custom;
in
{
options.services.wireguard-custom = {
enable = mkEnableOption "WireGuard VPN";
mode = mkOption {
type = types.enum [ "server" "client" ];
};
serverConfig = mkOption {
type = types.submodule {
options = {
address = mkOption {
type = types.str;
example = "10.2.2.1/24";
};
peers = mkOption {
type = types.listOf (types.submodule {
options = {
publicKey = mkOption { type = types.str; };
allowedIPs = mkOption { type = types.listOf types.str; };
};
});
default = [];
};
};
};
};
clientConfig = mkOption {
type = types.submodule {
options = {
address = mkOption {
type = types.str;
example = "10.2.2.2/24";
};
serverPublicKey = mkOption { type = types.str; };
serverEndpoint = mkOption {
type = types.str;
example = "vpn.example.com:51820";
};
allowedIPs = mkOption {
type = types.listOf types.str;
default = [ "10.2.2.0/24" ];
};
};
};
};
};
config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.wireguard-tools ];
systemd.tmpfiles.rules = [
"d /etc/wireguard 0700 root root - -"
"f /etc/wireguard/private.key 0600 root root - -"
];
systemd.services.wireguard-keygen = {
description = "Generate WireGuard private key";
before = [ "wg-quick-wg0.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
if [ ! -s /etc/wireguard/private.key ]; then
${pkgs.wireguard-tools}/bin/wg genkey > /etc/wireguard/private.key
chmod 600 /etc/wireguard/private.key
echo "Public key: $(${pkgs.wireguard-tools}/bin/wg pubkey < /etc/wireguard/private.key)"
fi
'';
};
networking.wg-quick.interfaces.wg0 = mkMerge [
{ privateKeyFile = "/etc/wireguard/private.key"; }
(mkIf (cfg.mode == "server") {
address = [ cfg.serverConfig.address ];
listenPort = 51820;
peers = map (peer: {
inherit (peer) publicKey allowedIPs;
}) cfg.serverConfig.peers;
})
(mkIf (cfg.mode == "client") {
address = [ cfg.clientConfig.address ];
peers = [{
publicKey = cfg.clientConfig.serverPublicKey;
allowedIPs = cfg.clientConfig.allowedIPs;
endpoint = cfg.clientConfig.serverEndpoint;
persistentKeepalive = 25;
}];
})
];
networking.firewall = mkMerge [
(mkIf (cfg.mode == "server") {
allowedUDPPorts = [ 51820 ];
})
{ trustedInterfaces = [ "wg0" ]; }
];
};
}