vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / services / networking / tailscale-derper.nix
blob9549cc5c6640014497127d2907e5658f72905f21
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
8 let
9   cfg = config.services.tailscale.derper;
12   meta.maintainers = with lib.maintainers; [ SuperSandro2000 ];
14   options = {
15     services.tailscale.derper = {
16       enable = lib.mkEnableOption "Tailscale Derper. See upstream doc <https://tailscale.com/kb/1118/custom-derp-servers> how to configure it on clients";
18       domain = lib.mkOption {
19         type = lib.types.str;
20         description = "Domain name under which the derper server is reachable.";
21       };
23       openFirewall = lib.mkOption {
24         type = lib.types.bool;
25         default = true;
26         description = ''
27           Whether to open the firewall for the specified port.
28           Derper requires the used ports to be opened, otherwise it doesn't work as expected.
29         '';
30       };
32       package = lib.mkPackageOption pkgs [
33         "tailscale"
34         "derper"
35       ] { };
37       stunPort = lib.mkOption {
38         type = lib.types.port;
39         default = 3478;
40         description = ''
41           STUN port to listen on.
42           See online docs <https://tailscale.com/kb/1118/custom-derp-servers#prerequisites> on how to configure a different external port.
43         '';
44       };
46       port = lib.mkOption {
47         type = lib.types.port;
48         default = 8010;
49         description = "The port the derper process will listen on. This is not the port tailscale will connect to.";
50       };
52       verifyClients = lib.mkOption {
53         type = lib.types.bool;
54         default = false;
55         description = ''
56           Whether to verify clients against a locally running tailscale daemon if they are allowed to connect to this node or not.
57         '';
58       };
59     };
60   };
62   config = lib.mkIf cfg.enable {
63     networking.firewall = lib.mkIf cfg.openFirewall {
64       # port 80 and 443 are opened by nginx already
65       allowedUDPPorts = [ cfg.stunPort ];
66     };
68     services = {
69       nginx = {
70         enable = true;
71         upstreams.tailscale-derper = {
72           servers."127.0.0.1:${toString cfg.port}" = { };
73           extraConfig = ''
74             keepalive 64;
75           '';
76         };
77         virtualHosts."${cfg.domain}" = {
78           addSSL = true; # this cannot be forceSSL as derper sends some information over port 80, too.
79           locations."/" = {
80             proxyPass = "http://tailscale-derper";
81             proxyWebsockets = true;
82             extraConfig = ''
83               keepalive_timeout 0;
84               proxy_buffering off;
85             '';
86           };
87         };
88       };
90       tailscale.enable = lib.mkIf cfg.verifyClients true;
91     };
93     systemd.services.tailscale-derper = {
94       serviceConfig = {
95         ExecStart =
96           "${lib.getExe' cfg.package "derper"} -a :${toString cfg.port} -c /var/lib/derper/derper.key -hostname=${cfg.domain} -stun-port ${toString cfg.stunPort}"
97           + lib.optionalString cfg.verifyClients " -verify-clients";
98         DynamicUser = true;
99         Restart = "always";
100         RestartSec = "5sec"; # don't crash loop immediately
101         StateDirectory = "derper";
102         Type = "simple";
104         CapabilityBoundingSet = [ "" ];
105         DeviceAllow = null;
106         LockPersonality = true;
107         NoNewPrivileges = true;
108         MemoryDenyWriteExecute = true;
109         PrivateDevices = true;
110         PrivateUsers = true;
111         ProcSubset = "pid";
112         ProtectClock = true;
113         ProtectControlGroups = true;
114         ProtectHostname = true;
115         ProtectKernelLogs = true;
116         ProtectKernelModules = true;
117         ProtectKernelTunables = true;
118         ProtectProc = "invisible";
119         RestrictAddressFamilies = [
120           "AF_INET"
121           "AF_INET6"
122           "AF_UNIX"
123         ];
124         RestrictNamespaces = true;
125         RestrictRealtime = true;
126         SystemCallArchitectures = "native";
127         SystemCallFilter = [ "@system-service" ];
128       };
129       wantedBy = [ "multi-user.target" ];
130     };
131   };