at master 6.1 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.services.dsnet; 10 settingsFormat = pkgs.formats.json { }; 11 patchFile = settingsFormat.generate "dsnet-patch.json" cfg.settings; 12in 13{ 14 options.services.dsnet = { 15 enable = lib.mkEnableOption "dsnet, a centralised Wireguard VPN manager"; 16 17 package = lib.mkPackageOption pkgs "dsnet" { }; 18 19 settings = lib.mkOption { 20 type = lib.types.submodule { 21 22 freeformType = settingsFormat.type; 23 24 options = { 25 ExternalHostname = lib.mkOption { 26 type = lib.types.nullOr lib.types.str; 27 default = null; 28 example = "vpn.example.com"; 29 description = '' 30 The hostname that clients should use to connect to this server. 31 This is used to generate the client configuration files. 32 33 This is preferred over ExternalIP, as it allows for IPv4 and 34 IPv6, as well as enabling the ability tp change IP. 35 ''; 36 }; 37 38 ExternalIP = lib.mkOption { 39 type = lib.types.nullOr lib.types.str; 40 default = null; 41 example = "192.0.2.1"; 42 description = '' 43 The external IP address of the server. This is used to generate 44 the client configuration files for when an ExternalHostname is not set. 45 46 Leaving this empty will cause dsnet to use the IP address of 47 what looks like the WAN interface. 48 ''; 49 }; 50 51 ExternalIP6 = lib.mkOption { 52 type = lib.types.nullOr lib.types.str; 53 default = null; 54 example = "2001:db8::1"; 55 description = '' 56 The external IPv6 address of the server. This is used to generate 57 the client configuration files for when an ExternalHostname is 58 not set. Used in preference to ExternalIP. 59 60 Leaving this empty will cause dsnet to use the IP address of 61 what looks like the WAN interface. 62 ''; 63 }; 64 65 Network = lib.mkOption { 66 type = lib.types.nullOr lib.types.str; 67 default = null; 68 example = "172.18.0.0/24"; 69 description = '' 70 The IPv4 network that the server will use to allocate IPs on the network. 71 Leave this empty to let dsnet choose a network. 72 ''; 73 }; 74 75 Network6 = lib.mkOption { 76 type = lib.types.nullOr lib.types.str; 77 default = null; 78 example = "2001:db8::1/64"; 79 description = '' 80 The IPv6 network that the server will use to allocate IPs on the 81 network. 82 Leave this empty to let dsnet choose a network. 83 ''; 84 }; 85 86 IP = lib.mkOption { 87 type = lib.types.nullOr lib.types.str; 88 default = null; 89 example = "172.18.0.1"; 90 description = '' 91 The IPv4 address that the server will use on the network. 92 Leave this empty to let dsnet choose an address. 93 ''; 94 }; 95 96 IP6 = lib.mkOption { 97 type = lib.types.nullOr lib.types.str; 98 default = null; 99 example = "2001:db8::1"; 100 description = '' 101 The IPv6 address that the server will use on the network 102 Leave this empty to let dsnet choose an address. 103 ''; 104 }; 105 106 Networks = lib.mkOption { 107 type = lib.types.nullOr (lib.types.listOf lib.types.str); 108 default = null; 109 example = [ 110 "0.0.0.0/0" 111 "192.168.0.0/24" 112 ]; 113 description = '' 114 The CIDR networks that should route through this server. Clients 115 will be configured to route traffic for these networks through 116 the server peer. 117 ''; 118 }; 119 }; 120 }; 121 122 default = { }; 123 description = '' 124 The settings to use for dsnet. This will be converted to a JSON 125 object that will be passed to dsnet as a patch, using the patch 126 command when the service is started. See the dsnet documentation for 127 more information on the additional options. 128 129 Note that the resulting /etc/dsnetconfg.json is more of a database 130 than it is a configuration file. It is therefore recommended that 131 system specific values are configured here, rather than the full 132 configuration including peers. 133 134 Peers may be managed via the dsnet add/remove commands, negating the 135 need to manage key material and cumbersom configuration with nix. If 136 you want peer configuration in nix, you may as well use the regular 137 wireguard module. 138 ''; 139 example = { 140 ExternalHostname = "vpn.example.com"; 141 ExternalIP = "127.0.0.1"; 142 ExternalIP6 = ""; 143 ListenPort = 51820; 144 Network = "10.3.148.0/22"; 145 Network6 = ""; 146 IP = "10.3.148.1"; 147 IP6 = ""; 148 DNS = "8.8.8.8"; 149 Networks = [ "0.0.0.0/0" ]; 150 }; 151 }; 152 }; 153 154 config = lib.mkIf cfg.enable { 155 environment.systemPackages = [ cfg.package ]; 156 157 systemd.services.dsnet = { 158 description = "dsnet VPN Management"; 159 after = [ "network-online.target" ]; 160 wants = [ "network-online.target" ]; 161 wantedBy = [ "multi-user.target" ]; 162 preStart = '' 163 test ! -f /etc/dsnetconfig.json && ${lib.getExe cfg.package} init 164 ${lib.getExe cfg.package} patch < ${patchFile} 165 ''; 166 serviceConfig = { 167 ExecStart = "${lib.getExe cfg.package} up"; 168 ExecStop = "${lib.getExe cfg.package} down"; 169 Type = "oneshot"; 170 # consider the service to be active after process exits, so it can be 171 # reloaded 172 RemainAfterExit = true; 173 }; 174 175 reload = '' 176 ${lib.getExe cfg.package} patch < ${patchFile} 177 ${lib.getExe cfg.package} sync < ${patchFile} 178 ''; 179 180 # reload _instead_ of restarting on change 181 reloadIfChanged = true; 182 }; 183 }; 184}