1{ config, lib, pkgs, utils, ... }: 2with lib; 3let 4 cfg = config.services.unifi; 5 stateDir = "/var/lib/unifi"; 6 cmd = "@${pkgs.jre}/bin/java java -jar ${stateDir}/lib/ace.jar"; 7 mountPoints = [ 8 { 9 what = "${pkgs.unifi}/dl"; 10 where = "${stateDir}/dl"; 11 } 12 { 13 what = "${pkgs.unifi}/lib"; 14 where = "${stateDir}/lib"; 15 } 16 { 17 what = "${pkgs.mongodb}/bin"; 18 where = "${stateDir}/bin"; 19 } 20 ]; 21 systemdMountPoints = map (m: "${utils.escapeSystemdPath m.where}.mount") mountPoints; 22in 23{ 24 25 options = { 26 27 services.unifi.enable = mkOption { 28 type = types.bool; 29 default = false; 30 description = '' 31 Whether or not to enable the unifi controller service. 32 ''; 33 }; 34 35 }; 36 37 config = mkIf cfg.enable { 38 39 users.extraUsers.unifi = { 40 uid = config.ids.uids.unifi; 41 description = "UniFi controller daemon user"; 42 home = "${stateDir}"; 43 }; 44 45 # We must create the binary directories as bind mounts instead of symlinks 46 # This is because the controller resolves all symlinks to absolute paths 47 # to be used as the working directory. 48 systemd.mounts = map ({ what, where }: { 49 bindsTo = [ "unifi.service" ]; 50 partOf = [ "unifi.service" ]; 51 unitConfig.RequiresMountsFor = stateDir; 52 options = "bind"; 53 what = what; 54 where = where; 55 }) mountPoints; 56 57 systemd.services.unifi = { 58 description = "UniFi controller daemon"; 59 wantedBy = [ "multi-user.target" ]; 60 after = [ "network.target" ] ++ systemdMountPoints; 61 partOf = systemdMountPoints; 62 bindsTo = systemdMountPoints; 63 unitConfig.RequiresMountsFor = stateDir; 64 # This a HACK to fix missing dependencies of dynamic libs extracted from jars 65 environment.LD_LIBRARY_PATH = with pkgs.stdenv; "${cc.cc}/lib"; 66 67 preStart = '' 68 # Ensure privacy of state 69 chown unifi "${stateDir}" 70 chmod 0700 "${stateDir}" 71 72 # Create the volatile webapps 73 rm -rf "${stateDir}/webapps" 74 mkdir -p "${stateDir}/webapps" 75 chown unifi "${stateDir}/webapps" 76 ln -s "${pkgs.unifi}/webapps/ROOT" "${stateDir}/webapps/ROOT" 77 ''; 78 79 postStop = '' 80 rm -rf "${stateDir}/webapps" 81 ''; 82 83 serviceConfig = { 84 Type = "simple"; 85 ExecStart = "${cmd} start"; 86 ExecStop = "${cmd} stop"; 87 User = "unifi"; 88 PermissionsStartOnly = true; 89 UMask = "0077"; 90 WorkingDirectory = "${stateDir}"; 91 }; 92 }; 93 94 }; 95 96}