{ config, lib, pkgs, ... }: let cfg = config.services.uxplay; in { options.services.uxplay = { enable = lib.mkEnableOption "uxplay, an Airplay mirroring server"; package = lib.mkPackageOption pkgs "uxplay" { }; extraArgs = lib.mkOption { type = with lib.types; listOf str; description = '' Extra arguments to passed onto the service executable. ''; default = [ ]; example = [ "-p" "4747" ]; }; }; config = lib.mkIf cfg.enable { # UXPlay requires a DNS-SD server so we'll enable Avahi. services.avahi.enable = lib.mkDefault true; services.avahi.publish.enable = lib.mkDefault true; services.avahi.publish.userServices = lib.mkDefault true; # We also have enabled mDNS since we're already using Avahi anyways. services.avahi.nssmdns4 = lib.mkDefault true; services.avahi.nssmdns6 = lib.mkDefault true; systemd.services.uxplay = { description = "Airplay mirroring server"; after = [ "network.target" ]; documentation = [ "man:uxplay(1)" ]; wantedBy = [ "multi-user.target" ]; script = "${lib.getExe' cfg.package "uxplay"} ${lib.escapeShellArgs cfg.extraArgs}"; serviceConfig = { DynamicUser = true; User = "uxplay"; Group = "uxplay"; RuntimeDirectory = "uxplay"; Restart = "on-failure"; LockPersonality = true; NoNewPrivileges = true; MemoryDenyWriteExecute = true; CapabilityBoundSet = lib.mkForce [ ]; PrivateTmp = true; PrivateUsers = true; PrivateDevices = true; ProtectControlGroups = true; ProtectClock = true; ProtectHome = true; ProtectHostname = true; ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; RestrictRealtime = true; RestrictAddressFamilies = [ "AF_LOCAL" "AF_INET" "AF_INET6" ]; RestrictNamespaces = true; SystemCallFilter = [ "@system-service" "~@privileged" ]; SystemCallArchitectures = "native"; SystemCallErrorNumber = "EPERM"; }; unitConfig = { StartLimitBurst = 5; StartLimitIntervalSec = 10; }; }; }; }