at 16.09-beta 3.8 kB view raw
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 what = "${cfg.dataDir}"; 22 where = "${stateDir}/data"; 23 } 24 ]; 25 systemdMountPoints = map (m: "${utils.escapeSystemdPath m.where}.mount") mountPoints; 26in 27{ 28 29 options = { 30 31 services.unifi.enable = mkOption { 32 type = types.bool; 33 default = false; 34 description = '' 35 Whether or not to enable the unifi controller service. 36 ''; 37 }; 38 39 services.unifi.dataDir = mkOption { 40 type = types.str; 41 default = "${stateDir}/data"; 42 description = '' 43 Where to store the database and other data. 44 45 This directory will be bind-mounted to ${stateDir}/data as part of the service startup. 46 ''; 47 }; 48 49 services.unifi.openPorts = mkOption { 50 type = types.bool; 51 default = true; 52 description = '' 53 Whether or not to open the minimum required ports on the firewall. 54 55 This is necessary to allow firmware upgrades and device discovery to 56 work. For remote login, you should additionally open (or forward) port 57 8443. 58 ''; 59 }; 60 61 }; 62 63 config = mkIf cfg.enable { 64 65 users.extraUsers.unifi = { 66 uid = config.ids.uids.unifi; 67 description = "UniFi controller daemon user"; 68 home = "${stateDir}"; 69 }; 70 71 networking.firewall = mkIf cfg.openPorts { 72 # https://help.ubnt.com/hc/en-us/articles/204910084-UniFi-Change-Default-Ports-for-Controller-and-UAPs 73 allowedTCPPorts = [ 74 8080 # Port for UAP to inform controller. 75 8880 # Port for HTTP portal redirect, if guest portal is enabled. 76 8843 # Port for HTTPS portal redirect, ditto. 77 ]; 78 allowedUDPPorts = [ 79 3478 # UDP port used for STUN. 80 10001 # UDP port used for device discovery. 81 ]; 82 }; 83 84 # We must create the binary directories as bind mounts instead of symlinks 85 # This is because the controller resolves all symlinks to absolute paths 86 # to be used as the working directory. 87 systemd.mounts = map ({ what, where }: { 88 bindsTo = [ "unifi.service" ]; 89 partOf = [ "unifi.service" ]; 90 unitConfig.RequiresMountsFor = stateDir; 91 options = "bind"; 92 what = what; 93 where = where; 94 }) mountPoints; 95 96 systemd.services.unifi = { 97 description = "UniFi controller daemon"; 98 wantedBy = [ "multi-user.target" ]; 99 after = [ "network.target" ] ++ systemdMountPoints; 100 partOf = systemdMountPoints; 101 bindsTo = systemdMountPoints; 102 unitConfig.RequiresMountsFor = stateDir; 103 # This a HACK to fix missing dependencies of dynamic libs extracted from jars 104 environment.LD_LIBRARY_PATH = with pkgs.stdenv; "${cc.cc.lib}/lib"; 105 106 preStart = '' 107 # Ensure privacy of state and data. 108 chown unifi "${stateDir}" "${stateDir}/data" 109 chmod 0700 "${stateDir}" "${stateDir}/data" 110 111 # Create the volatile webapps 112 rm -rf "${stateDir}/webapps" 113 mkdir -p "${stateDir}/webapps" 114 chown unifi "${stateDir}/webapps" 115 ln -s "${pkgs.unifi}/webapps/ROOT" "${stateDir}/webapps/ROOT" 116 ''; 117 118 postStop = '' 119 rm -rf "${stateDir}/webapps" 120 ''; 121 122 serviceConfig = { 123 Type = "simple"; 124 ExecStart = "${cmd} start"; 125 ExecStop = "${cmd} stop"; 126 User = "unifi"; 127 PermissionsStartOnly = true; 128 UMask = "0077"; 129 WorkingDirectory = "${stateDir}"; 130 }; 131 }; 132 133 }; 134 135}