···
9
+
cfg = config.services.dsnet;
10
+
settingsFormat = pkgs.formats.json { };
11
+
patchFile = settingsFormat.generate "dsnet-patch.json" cfg.settings;
14
+
options.services.dsnet = {
15
+
enable = lib.mkEnableOption "dsnet, a centralised Wireguard VPN manager";
17
+
package = lib.mkPackageOption pkgs "dsnet" { };
19
+
settings = lib.mkOption {
20
+
type = lib.types.submodule {
22
+
freeformType = settingsFormat.type;
25
+
ExternalHostname = lib.mkOption {
26
+
type = lib.types.nullOr lib.types.str;
28
+
example = "vpn.example.com";
30
+
The hostname that clients should use to connect to this server.
31
+
This is used to generate the client configuration files.
33
+
This is preferred over ExternalIP, as it allows for IPv4 and
34
+
IPv6, as well as enabling the ability tp change IP.
38
+
ExternalIP = lib.mkOption {
39
+
type = lib.types.nullOr lib.types.str;
41
+
example = "192.0.2.1";
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.
46
+
Leaving this empty will cause dsnet to use the IP address of
47
+
what looks like the WAN interface.
51
+
ExternalIP6 = lib.mkOption {
52
+
type = lib.types.nullOr lib.types.str;
54
+
example = "2001:db8::1";
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.
60
+
Leaving this empty will cause dsnet to use the IP address of
61
+
what looks like the WAN interface.
65
+
Network = lib.mkOption {
66
+
type = lib.types.nullOr lib.types.str;
68
+
example = "172.18.0.0/24";
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.
75
+
Network6 = lib.mkOption {
76
+
type = lib.types.nullOr lib.types.str;
78
+
example = "2001:db8::1/64";
80
+
The IPv6 network that the server will use to allocate IPs on the
82
+
Leave this empty to let dsnet choose a network.
87
+
type = lib.types.nullOr lib.types.str;
89
+
example = "172.18.0.1";
91
+
The IPv4 address that the server will use on the network.
92
+
Leave this empty to let dsnet choose an address.
96
+
IP6 = lib.mkOption {
97
+
type = lib.types.nullOr lib.types.str;
99
+
example = "2001:db8::1";
101
+
The IPv6 address that the server will use on the network
102
+
Leave this empty to let dsnet choose an address.
106
+
Networks = lib.mkOption {
107
+
type = lib.types.nullOr (lib.types.listOf lib.types.str);
114
+
The CIDR networks that should route through this server. Clients
115
+
will be configured to route traffic for these networks through
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.
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.
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
140
+
ExternalHostname = "vpn.example.com";
141
+
ExternalIP = "127.0.0.1";
143
+
ListenPort = 51820;
144
+
Network = "10.3.148.0/22";
149
+
Networks = [ "0.0.0.0/0" ];
154
+
config = lib.mkIf cfg.enable {
155
+
environment.systemPackages = [ cfg.package ];
157
+
systemd.services.dsnet = {
158
+
description = "dsnet VPN Management";
159
+
after = [ "network-online.target" ];
160
+
wants = [ "network-online.target" ];
161
+
wantedBy = [ "multi-user.target" ];
163
+
test ! -f /etc/dsnetconfig.json && ${lib.getExe cfg.package} init
164
+
${lib.getExe cfg.package} patch < ${patchFile}
167
+
ExecStart = "${lib.getExe cfg.package} up";
168
+
ExecStop = "${lib.getExe cfg.package} down";
170
+
# consider the service to be active after process exits, so it can be
172
+
RemainAfterExit = true;
176
+
${lib.getExe cfg.package} patch < ${patchFile}
177
+
${lib.getExe cfg.package} sync < ${patchFile}
180
+
# reload _instead_ of restarting on change
181
+
reloadIfChanged = true;