self: { config, lib, pkgs, ... }: let cfg = config.services.puppy-tracker; staticPkg = self.packages.${pkgs.system}.static; serverPkg = self.packages.${pkgs.system}.server; in { options.services.puppy-tracker = { enable = lib.mkEnableOption "Puppy Tracker (offline-first puppy tracking app with sync server)"; address = lib.mkOption { type = lib.types.str; default = "0.0.0.0"; description = "Address the server listens on."; }; port = lib.mkOption { type = lib.types.port; default = 8080; description = "TCP port the server listens on."; }; openFirewall = lib.mkOption { type = lib.types.bool; default = false; description = "Whether to open the configured port in the firewall."; }; package = lib.mkOption { type = lib.types.package; default = serverPkg; defaultText = lib.literalExpression "puppy-tracker.packages.\${system}.server"; description = "The puppy-tracker server package."; }; staticPackage = lib.mkOption { type = lib.types.package; default = staticPkg; defaultText = lib.literalExpression "puppy-tracker.packages.\${system}.static"; description = "The puppy-tracker static-site package (HTML/CSS/JS)."; }; }; config = lib.mkIf cfg.enable { systemd.services.puppy-tracker = { description = "Puppy Tracker server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { ExecStart = lib.concatStringsSep " " [ "${cfg.package}/bin/puppy-tracker-server" "-addr ${cfg.address}:${toString cfg.port}" "-static ${cfg.staticPackage}/share/puppy-tracker" "-data /var/lib/puppy-tracker/events.json" ]; DynamicUser = true; StateDirectory = "puppy-tracker"; StateDirectoryMode = "0750"; Restart = "on-failure"; RestartSec = "2s"; # Hardening ProtectSystem = "strict"; ProtectHome = true; PrivateTmp = true; PrivateDevices = true; NoNewPrivileges = true; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectKernelLogs = true; ProtectControlGroups = true; RestrictSUIDSGID = true; RestrictRealtime = true; LockPersonality = true; MemoryDenyWriteExecute = true; SystemCallArchitectures = "native"; SystemCallFilter = [ "@system-service" "~@privileged @resources" ]; RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; }; }; networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ]; }; }