Self-host your own digital island
1{ pkgs, config, lib, ... }: 2 3with lib; 4 5let cfg = config.wireguard; in 6{ 7 options.wireguard = { 8 enable = mkEnableOption "wireguard"; 9 server = mkOption { 10 type = with types; bool; 11 default = cfg.hosts.${config.networking.hostName}.server; 12 }; 13 hosts = 14 let hostOps = { ... }: { 15 options = { 16 ip = mkOption { 17 type = types.str; 18 }; 19 publicKey = mkOption { 20 type = types.str; 21 }; 22 server = mkOption { 23 type = types.bool; 24 default = false; 25 }; 26 endpoint = mkOption { 27 type = with types; nullOr str; 28 default = null; 29 # should not be null when server = true 30 }; 31 persistentKeepalive = mkOption { 32 type = with types; nullOr int; 33 default = null; 34 }; 35 }; 36 }; 37 in mkOption { 38 type = with types; attrsOf (submodule hostOps); 39 }; 40 }; 41 42 config = mkIf cfg.enable { 43 environment.systemPackages = with pkgs; [ wireguard-tools ]; 44 networking = { 45 # populate /etc/hosts with hostnames and IPs 46 extraHosts = builtins.concatStringsSep "\n" ( 47 attrsets.mapAttrsToList ( 48 hostName: values: "${values.ip} ${hostName}" 49 ) cfg.hosts 50 ); 51 52 firewall = { 53 allowedUDPPorts = [ 51820 ]; 54 checkReversePath = false; 55 }; 56 57 wireguard = { 58 enable = true; 59 interfaces.wg0 = let hostName = config.networking.hostName; in { 60 ips = [ "${cfg.hosts."${hostName}".ip}/24" ]; 61 listenPort = 51820; 62 privateKeyFile = "${config.eilean.secretsDir}/wireguard-key-${hostName}"; 63 peers = 64 let 65 serverPeers = attrsets.mapAttrsToList 66 (hostName: values: 67 if values.server then 68 { 69 allowedIPs = [ "10.0.0.0/24" ]; 70 publicKey = values.publicKey; 71 endpoint = "${values.endpoint}:51820"; 72 persistentKeepalive = values.persistentKeepalive; 73 } 74 else {}) 75 cfg.hosts; 76 # remove empty elements 77 cleanedServerPeers = lists.remove { } serverPeers; 78 in mkIf (!cfg.server) cleanedServerPeers; 79 }; 80 }; 81 }; 82 }; 83}