python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / networking / unifi.nix
blobd30f7c89633b326b29ca001ace09b570c0ce1543
1 { config, options, lib, pkgs, utils, ... }:
2 with lib;
3 let
4   cfg = config.services.unifi;
5   stateDir = "/var/lib/unifi";
6   cmd = ''
7     @${cfg.jrePackage}/bin/java java \
8         ${optionalString (cfg.initialJavaHeapSize != null) "-Xms${(toString cfg.initialJavaHeapSize)}m"} \
9         ${optionalString (cfg.maximumJavaHeapSize != null) "-Xmx${(toString cfg.maximumJavaHeapSize)}m"} \
10         -jar ${stateDir}/lib/ace.jar
11   '';
15   options = {
17     services.unifi.enable = mkOption {
18       type = types.bool;
19       default = false;
20       description = lib.mdDoc ''
21         Whether or not to enable the unifi controller service.
22       '';
23     };
25     services.unifi.jrePackage = mkOption {
26       type = types.package;
27       default = pkgs.jre8;
28       defaultText = literalExpression "pkgs.jre8";
29       description = lib.mdDoc ''
30         The JRE package to use. Check the release notes to ensure it is supported.
31       '';
32     };
34     services.unifi.unifiPackage = mkOption {
35       type = types.package;
36       default = pkgs.unifiLTS;
37       defaultText = literalExpression "pkgs.unifiLTS";
38       description = lib.mdDoc ''
39         The unifi package to use.
40       '';
41     };
43     services.unifi.mongodbPackage = mkOption {
44       type = types.package;
45       default = pkgs.mongodb;
46       defaultText = literalExpression "pkgs.mongodb";
47       description = lib.mdDoc ''
48         The mongodb package to use.
49       '';
50     };
52     services.unifi.openFirewall = mkOption {
53       type = types.bool;
54       default = false;
55       description = lib.mdDoc ''
56         Whether or not to open the minimum required ports on the firewall.
58         This is necessary to allow firmware upgrades and device discovery to
59         work. For remote login, you should additionally open (or forward) port
60         8443.
61       '';
62     };
64     services.unifi.initialJavaHeapSize = mkOption {
65       type = types.nullOr types.int;
66       default = null;
67       example = 1024;
68       description = lib.mdDoc ''
69         Set the initial heap size for the JVM in MB. If this option isn't set, the
70         JVM will decide this value at runtime.
71       '';
72     };
74     services.unifi.maximumJavaHeapSize = mkOption {
75       type = types.nullOr types.int;
76       default = null;
77       example = 4096;
78       description = lib.mdDoc ''
79         Set the maximimum heap size for the JVM in MB. If this option isn't set, the
80         JVM will decide this value at runtime.
81       '';
82     };
84   };
86   config = mkIf cfg.enable {
88     users.users.unifi = {
89       isSystemUser = true;
90       group = "unifi";
91       description = "UniFi controller daemon user";
92       home = "${stateDir}";
93     };
94     users.groups.unifi = {};
96     networking.firewall = mkIf cfg.openFirewall {
97       # https://help.ubnt.com/hc/en-us/articles/218506997
98       allowedTCPPorts = [
99         8080  # Port for UAP to inform controller.
100         8880  # Port for HTTP portal redirect, if guest portal is enabled.
101         8843  # Port for HTTPS portal redirect, ditto.
102         6789  # Port for UniFi mobile speed test.
103       ];
104       allowedUDPPorts = [
105         3478  # UDP port used for STUN.
106         10001 # UDP port used for device discovery.
107       ];
108     };
110     systemd.services.unifi = {
111       description = "UniFi controller daemon";
112       wantedBy = [ "multi-user.target" ];
113       after = [ "network.target" ];
115       # This a HACK to fix missing dependencies of dynamic libs extracted from jars
116       environment.LD_LIBRARY_PATH = with pkgs.stdenv; "${cc.cc.lib}/lib";
117       # Make sure package upgrades trigger a service restart
118       restartTriggers = [ cfg.unifiPackage cfg.mongodbPackage ];
120       serviceConfig = {
121         Type = "simple";
122         ExecStart = "${(removeSuffix "\n" cmd)} start";
123         ExecStop = "${(removeSuffix "\n" cmd)} stop";
124         Restart = "on-failure";
125         TimeoutSec = "5min";
126         User = "unifi";
127         UMask = "0077";
128         WorkingDirectory = "${stateDir}";
129         # the stop command exits while the main process is still running, and unifi
130         # wants to manage its own child processes. this means we have to set KillSignal
131         # to something the main process ignores, otherwise every stop will have unifi.service
132         # fail with SIGTERM status.
133         KillSignal = "SIGCONT";
135         # Hardening
136         AmbientCapabilities = "";
137         CapabilityBoundingSet = "";
138         # ProtectClock= adds DeviceAllow=char-rtc r
139         DeviceAllow = "";
140         DevicePolicy = "closed";
141         LockPersonality = true;
142         NoNewPrivileges = true;
143         PrivateDevices = true;
144         PrivateMounts = true;
145         PrivateTmp = true;
146         PrivateUsers = true;
147         ProtectClock = true;
148         ProtectControlGroups = true;
149         ProtectHome = true;
150         ProtectHostname = true;
151         ProtectKernelLogs = true;
152         ProtectKernelModules = true;
153         ProtectKernelTunables = true;
154         ProtectSystem = "strict";
155         RemoveIPC = true;
156         RestrictNamespaces = true;
157         RestrictRealtime = true;
158         RestrictSUIDSGID = true;
159         SystemCallErrorNumber = "EPERM";
160         SystemCallFilter = [ "@system-service" ];
162         StateDirectory = "unifi";
163         RuntimeDirectory = "unifi";
164         LogsDirectory = "unifi";
165         CacheDirectory= "unifi";
167         TemporaryFileSystem = [
168           # required as we want to create bind mounts below
169           "${stateDir}/webapps:rw"
170         ];
172         # We must create the binary directories as bind mounts instead of symlinks
173         # This is because the controller resolves all symlinks to absolute paths
174         # to be used as the working directory.
175         BindPaths =  [
176           "/var/log/unifi:${stateDir}/logs"
177           "/run/unifi:${stateDir}/run"
178           "${cfg.unifiPackage}/dl:${stateDir}/dl"
179           "${cfg.unifiPackage}/lib:${stateDir}/lib"
180           "${cfg.mongodbPackage}/bin:${stateDir}/bin"
181           "${cfg.unifiPackage}/webapps/ROOT:${stateDir}/webapps/ROOT"
182         ];
184         # Needs network access
185         PrivateNetwork = false;
186         # Cannot be true due to OpenJDK
187         MemoryDenyWriteExecute = false;
188       };
189     };
191   };
192   imports = [
193     (mkRemovedOptionModule [ "services" "unifi" "dataDir" ] "You should move contents of dataDir to /var/lib/unifi/data" )
194     (mkRenamedOptionModule [ "services" "unifi" "openPorts" ] [ "services" "unifi" "openFirewall" ])
195   ];
197   meta.maintainers = with lib.maintainers; [ erictapen pennae ];