{ pkgs, lib, config, ... }: let cfg = config.services.ntfy-sh; settingsFormat = pkgs.formats.yaml { }; configFile = settingsFormat.generate "server.yml" cfg.settings; in { # We don't use the upstream module because it's stupid; the author # doesn't seem to understand `DynamicUser` (or at least be unaware of # systemd credentials). disabledModules = [ "services/misc/ntfy-sh.nix" ]; options.services.ntfy-sh = { enable = lib.mkEnableOption "[ntfy-sh](https://ntfy.sh), a push notification service"; package = lib.mkPackageOption pkgs "ntfy-sh" { }; environmentFile = lib.mkOption { type = lib.types.nullOr lib.types.path; default = null; description = '' Environment file; intended to be used for user provisioning. ''; }; settings = lib.mkOption { inherit (settingsFormat) type; default = { }; description = '' Configuration for ntfy.sh, supported values are [here](https://ntfy.sh/docs/config/#config-options). ''; }; }; config.systemd.services.ntfy-sh = { description = "Push notifications server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { Type = "exec"; ExecReload = "kill --signal HUP $MAINPID"; ExecStart = "${lib.getExe' cfg.package "ntfy"} serve -c ${configFile}"; EnvironmentFile = cfg.environmentFile; StateDirectory = "ntfy-sh"; DynamicUser = true; PrivateTmp = true; NoNewPrivileges = true; ProtectSystem = "full"; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectKernelLogs = true; ProtectControlGroups = true; PrivateDevices = true; RestrictSUIDSGID = true; RestrictNamespaces = true; RestrictRealtime = true; MemoryDenyWriteExecute = true; # Upstream Recommandation LimitNOFILE = 20500; }; }; }