{
  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;
    };
  };
}
