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}