{ config, lib, pkgs, ... }: let cfg = config.my.services.unifi; allowedRules = { # https://help.ubnt.com/hc/en-us/articles/218506997 allowedTCPPorts = [ 8080 # Port for UAP to inform controller. 8880 # Port for HTTP portal redirect, if guest portal is enabled. 8843 # Port for HTTPS portal redirect, ditto. 6789 # Port for UniFi mobile speed test. 9130 # Port for the prometheus exporter ]; allowedUDPPorts = [ 3478 # UDP port used for STUN. 10001 # UDP port used for device discovery. ]; }; in { options.my.services.unifi = with lib; { enable = mkEnableOption "Unifi controller"; }; config = lib.mkIf cfg.enable { networking.firewall = allowedRules; users.users.unifi.group = "unifi"; users.users.unifi.isSystemUser = true; users.groups.unifi = { }; services.unifi = { enable = true; openPorts = true; unifiPackage = pkgs.unifiStable; }; age.secrets.unifi-read-only = { file = ../../../secrets/unifi/unifi-poller.age; mode = "0400"; owner = "unifi-poller"; }; services.unifi-poller = { enable = true; unifi.defaults = { url = "https://127.0.0.1:8443"; user = "unifipoller"; pass = config.age.secrets.unifi-read-only.path; verify_ssl = false; }; influxdb.disable = true; prometheus = { http_listen = ":9130"; }; }; systemd.services.unifi-available = { description = "Wait for Unifi to be available"; after = [ "unifi.service" ]; before = [ "unifi-poller.service" ]; wantedBy = [ "unifi-poller.service" ]; serviceConfig = { ExecStart = "${pkgs.curl}/bin/curl --insecure 'https://localhost:8443/'"; Restart = "on-failure"; RestartSec = "10"; Type = "oneshot"; }; }; age.secrets.restic-repo-systems.file = ../../../secrets/restic/repo-systems.age; services.restic.backups = { unifi = { paths = [ "/var/lib/unifi" ]; repository = "/data/slow/backups/systems"; passwordFile = config.age.secrets.restic-repo-systems.path; initialize = true; timerConfig = { OnCalendar = "00:45"; }; extraBackupArgs = [ "--tag unifi" ]; pruneOpts = [ "--keep-daily 7" "--keep-weekly 4" ]; }; }; }; }