at 21.11-pre 5.4 kB view raw
1{ config, lib, pkgs, utils, ... }: 2with lib; 3let 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 ''; 12 mountPoints = [ 13 { 14 what = "${cfg.unifiPackage}/dl"; 15 where = "${stateDir}/dl"; 16 } 17 { 18 what = "${cfg.unifiPackage}/lib"; 19 where = "${stateDir}/lib"; 20 } 21 { 22 what = "${cfg.mongodbPackage}/bin"; 23 where = "${stateDir}/bin"; 24 } 25 { 26 what = "${cfg.dataDir}"; 27 where = "${stateDir}/data"; 28 } 29 ]; 30 systemdMountPoints = map (m: "${utils.escapeSystemdPath m.where}.mount") mountPoints; 31in 32{ 33 34 options = { 35 36 services.unifi.enable = mkOption { 37 type = types.bool; 38 default = false; 39 description = '' 40 Whether or not to enable the unifi controller service. 41 ''; 42 }; 43 44 services.unifi.jrePackage = mkOption { 45 type = types.package; 46 default = pkgs.jre8; 47 defaultText = "pkgs.jre8"; 48 description = '' 49 The JRE package to use. Check the release notes to ensure it is supported. 50 ''; 51 }; 52 53 services.unifi.unifiPackage = mkOption { 54 type = types.package; 55 default = pkgs.unifiLTS; 56 defaultText = "pkgs.unifiLTS"; 57 description = '' 58 The unifi package to use. 59 ''; 60 }; 61 62 services.unifi.mongodbPackage = mkOption { 63 type = types.package; 64 default = pkgs.mongodb; 65 defaultText = "pkgs.mongodb"; 66 description = '' 67 The mongodb package to use. 68 ''; 69 }; 70 71 services.unifi.dataDir = mkOption { 72 type = types.str; 73 default = "${stateDir}/data"; 74 description = '' 75 Where to store the database and other data. 76 77 This directory will be bind-mounted to ${stateDir}/data as part of the service startup. 78 ''; 79 }; 80 81 services.unifi.openPorts = mkOption { 82 type = types.bool; 83 default = true; 84 description = '' 85 Whether or not to open the minimum required ports on the firewall. 86 87 This is necessary to allow firmware upgrades and device discovery to 88 work. For remote login, you should additionally open (or forward) port 89 8443. 90 ''; 91 }; 92 93 services.unifi.initialJavaHeapSize = mkOption { 94 type = types.nullOr types.int; 95 default = null; 96 example = 1024; 97 description = '' 98 Set the initial heap size for the JVM in MB. If this option isn't set, the 99 JVM will decide this value at runtime. 100 ''; 101 }; 102 103 services.unifi.maximumJavaHeapSize = mkOption { 104 type = types.nullOr types.int; 105 default = null; 106 example = 4096; 107 description = '' 108 Set the maximimum heap size for the JVM in MB. If this option isn't set, the 109 JVM will decide this value at runtime. 110 ''; 111 }; 112 113 }; 114 115 config = mkIf cfg.enable { 116 117 users.users.unifi = { 118 uid = config.ids.uids.unifi; 119 description = "UniFi controller daemon user"; 120 home = "${stateDir}"; 121 }; 122 123 networking.firewall = mkIf cfg.openPorts { 124 # https://help.ubnt.com/hc/en-us/articles/218506997 125 allowedTCPPorts = [ 126 8080 # Port for UAP to inform controller. 127 8880 # Port for HTTP portal redirect, if guest portal is enabled. 128 8843 # Port for HTTPS portal redirect, ditto. 129 6789 # Port for UniFi mobile speed test. 130 ]; 131 allowedUDPPorts = [ 132 3478 # UDP port used for STUN. 133 10001 # UDP port used for device discovery. 134 ]; 135 }; 136 137 # We must create the binary directories as bind mounts instead of symlinks 138 # This is because the controller resolves all symlinks to absolute paths 139 # to be used as the working directory. 140 systemd.mounts = map ({ what, where }: { 141 bindsTo = [ "unifi.service" ]; 142 partOf = [ "unifi.service" ]; 143 unitConfig.RequiresMountsFor = stateDir; 144 options = "bind"; 145 what = what; 146 where = where; 147 }) mountPoints; 148 149 systemd.tmpfiles.rules = [ 150 "d '${stateDir}' 0700 unifi - - -" 151 "d '${stateDir}/data' 0700 unifi - - -" 152 "d '${stateDir}/webapps' 0700 unifi - - -" 153 "L+ '${stateDir}/webapps/ROOT' - - - - ${cfg.unifiPackage}/webapps/ROOT" 154 ]; 155 156 systemd.services.unifi = { 157 description = "UniFi controller daemon"; 158 wantedBy = [ "multi-user.target" ]; 159 after = [ "network.target" ] ++ systemdMountPoints; 160 partOf = systemdMountPoints; 161 bindsTo = systemdMountPoints; 162 unitConfig.RequiresMountsFor = stateDir; 163 # This a HACK to fix missing dependencies of dynamic libs extracted from jars 164 environment.LD_LIBRARY_PATH = with pkgs.stdenv; "${cc.cc.lib}/lib"; 165 # Make sure package upgrades trigger a service restart 166 restartTriggers = [ cfg.unifiPackage cfg.mongodbPackage ]; 167 168 serviceConfig = { 169 Type = "simple"; 170 ExecStart = "${(removeSuffix "\n" cmd)} start"; 171 ExecStop = "${(removeSuffix "\n" cmd)} stop"; 172 Restart = "on-failure"; 173 User = "unifi"; 174 UMask = "0077"; 175 WorkingDirectory = "${stateDir}"; 176 }; 177 }; 178 179 }; 180 181 meta.maintainers = with lib.maintainers; [ erictapen ]; 182}