1 { config, lib, options, pkgs, utils, ... }:
4 cfg = config.services.unifi-video;
5 opt = options.services.unifi-video;
6 mainClass = "com.ubnt.airvision.Main";
8 ${pkgs.jsvc}/bin/jsvc \
14 -home ${cfg.jrePackage}/lib/openjdk \
15 -cp ${pkgs.commonsDaemon}/share/java/commons-daemon-1.2.4.jar:${stateDir}/lib/airvision.jar \
16 -pidfile ${cfg.pidFile} \
17 -procname unifi-video \
18 -Djava.security.egd=file:/dev/./urandom \
19 -Xmx${toString cfg.maximumJavaHeapSize}M \
22 -XX:+UseStringDeduplication \
23 -XX:MaxMetaspaceSize=768M \
24 -Djava.library.path=${stateDir}/lib \
25 -Djava.awt.headless=true \
26 -Djavax.net.ssl.trustStore=${stateDir}/etc/ufv-truststore \
27 -Dfile.encoding=UTF-8 \
28 -Dav.tempdir=/var/cache/unifi-video
31 mongoConf = pkgs.writeTextFile {
35 # for documentation of all options, see http://docs.mongodb.org/manual/reference/configuration-options/
38 dbPath: ${cfg.dataDir}/db
46 path: ${stateDir}/logs/mongod.log
55 slowOpThresholdMs: 500
61 mongoWtConf = pkgs.writeTextFile {
62 name = "mongowt.conf";
65 # for documentation of all options, see:
66 # http://docs.mongodb.org/manual/reference/configuration-options/
69 dbPath: ${cfg.dataDir}/db-wt
86 slowOpThresholdMs: 500
91 stateDir = "/var/lib/unifi-video";
96 options.services.unifi-video = {
101 description = lib.mdDoc ''
102 Whether or not to enable the unifi-video service.
106 jrePackage = mkOption {
107 type = types.package;
109 defaultText = literalExpression "pkgs.jre8";
110 description = lib.mdDoc ''
111 The JRE package to use. Check the release notes to ensure it is supported.
115 unifiVideoPackage = mkOption {
116 type = types.package;
117 default = pkgs.unifi-video;
118 defaultText = literalExpression "pkgs.unifi-video";
119 description = lib.mdDoc ''
120 The unifi-video package to use.
124 mongodbPackage = mkOption {
125 type = types.package;
126 default = pkgs.mongodb-4_0;
127 defaultText = literalExpression "pkgs.mongodb";
128 description = lib.mdDoc ''
129 The mongodb package to use.
135 default = "${stateDir}/logs";
136 description = lib.mdDoc ''
137 Where to store the logs.
143 default = "${stateDir}/data";
144 description = lib.mdDoc ''
145 Where to store the database and other data.
149 openFirewall = mkOption {
152 description = lib.mdDoc ''
153 Whether or not to open the required ports on the firewall.
157 maximumJavaHeapSize = mkOption {
158 type = types.nullOr types.int;
161 description = lib.mdDoc ''
162 Set the maximimum heap size for the JVM in MB.
168 default = "${cfg.dataDir}/unifi-video.pid";
169 defaultText = literalExpression ''"''${config.${opt.dataDir}}/unifi-video.pid"'';
170 description = lib.mdDoc "Location of unifi-video pid file.";
175 config = mkIf cfg.enable {
178 (options.services.unifi-video.openFirewall.highestPrio >= (mkOptionDefault null).priority)
179 "The current services.unifi-video.openFirewall = true default is deprecated and will change to false in 22.11. Set it explicitly to silence this warning.";
181 users.users.unifi-video = {
182 description = "UniFi Video controller daemon user";
184 group = "unifi-video";
187 users.groups.unifi-video = {};
189 networking.firewall = mkIf cfg.openFirewall {
190 # https://help.ui.com/hc/en-us/articles/217875218-UniFi-Video-Ports-Used
194 7445 # Video over HTTP (mobile app)
195 7446 # Video over HTTPS (mobile app)
196 7447 # RTSP via the controller
197 7442 # Camera management from cameras to NVR over WAN
200 6666 # Inbound camera streams sent over WAN
204 systemd.tmpfiles.rules = [
205 "d '${stateDir}' 0700 unifi-video unifi-video - -"
206 "d '/var/cache/unifi-video' 0700 unifi-video unifi-video - -"
208 "d '${stateDir}/logs' 0700 unifi-video unifi-video - -"
209 "C '${stateDir}/etc' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/etc"
210 "C '${stateDir}/webapps' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/webapps"
211 "C '${stateDir}/email' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/email"
212 "C '${stateDir}/fw' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/fw"
213 "C '${stateDir}/lib' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/lib"
215 "d '${stateDir}/data' 0700 unifi-video unifi-video - -"
216 "d '${stateDir}/data/db' 0700 unifi-video unifi-video - -"
217 "C '${stateDir}/data/system.properties' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/etc/system.properties"
219 "d '${stateDir}/bin' 0700 unifi-video unifi-video - -"
220 "f '${stateDir}/bin/evostreamms' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/evostreamms"
221 "f '${stateDir}/bin/libavcodec.so.54' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/libavcodec.so.54"
222 "f '${stateDir}/bin/libavformat.so.54' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/libavformat.so.54"
223 "f '${stateDir}/bin/libavutil.so.52' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/libavutil.so.52"
224 "f '${stateDir}/bin/ubnt.avtool' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/ubnt.avtool"
225 "f '${stateDir}/bin/ubnt.updater' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/bin/ubnt.updater"
226 "C '${stateDir}/bin/mongo' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongo"
227 "C '${stateDir}/bin/mongod' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongod"
228 "C '${stateDir}/bin/mongoperf' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongoperf"
229 "C '${stateDir}/bin/mongos' 0700 unifi-video unifi-video - ${cfg.mongodbPackage}/bin/mongos"
231 "d '${stateDir}/conf' 0700 unifi-video unifi-video - -"
232 "C '${stateDir}/conf/evostream' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/evostream"
233 "Z '${stateDir}/conf/evostream' 0700 unifi-video unifi-video - -"
234 "L+ '${stateDir}/conf/mongodv3.0+.conf' 0700 unifi-video unifi-video - ${mongoConf}"
235 "L+ '${stateDir}/conf/mongodv3.6+.conf' 0700 unifi-video unifi-video - ${mongoConf}"
236 "L+ '${stateDir}/conf/mongod-wt.conf' 0700 unifi-video unifi-video - ${mongoWtConf}"
237 "L+ '${stateDir}/conf/catalina.policy' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/catalina.policy"
238 "L+ '${stateDir}/conf/catalina.properties' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/catalina.properties"
239 "L+ '${stateDir}/conf/context.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/context.xml"
240 "L+ '${stateDir}/conf/logging.properties' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/logging.properties"
241 "L+ '${stateDir}/conf/server.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/server.xml"
242 "L+ '${stateDir}/conf/tomcat-users.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/tomcat-users.xml"
243 "L+ '${stateDir}/conf/web.xml' 0700 unifi-video unifi-video - ${pkgs.unifi-video}/lib/unifi-video/conf/web.xml"
246 systemd.services.unifi-video = {
247 description = "UniFi Video NVR daemon";
248 wantedBy = [ "multi-user.target" ];
249 after = [ "network.target" ] ;
250 unitConfig.RequiresMountsFor = stateDir;
251 # Make sure package upgrades trigger a service restart
252 restartTriggers = [ cfg.unifiVideoPackage cfg.mongodbPackage ];
253 path = with pkgs; [ gawk coreutils busybox which jre8 lsb-release libcap util-linux ];
256 ExecStart = "${(removeSuffix "\n" cmd)} ${mainClass} start";
257 ExecStop = "${(removeSuffix "\n" cmd)} stop ${mainClass} stop";
258 Restart = "on-failure";
260 User = "unifi-video";
261 WorkingDirectory = "${stateDir}";
267 (mkRenamedOptionModule [ "services" "unifi-video" "openPorts" ] [ "services" "unifi-video" "openFirewall" ])
270 meta.maintainers = with lib.maintainers; [ rsynnest ];