{ lib, config, pkgs, ... }: let cfg = config.services.activity-relay; configFile = pkgs.writeText "activity-relay.json" ( builtins.toJSON ({ ACTOR_PEM = cfg.actorPem.path; REDIS_URL = cfg.redisUrl; RELAY_BIND = cfg.relay.bind; RELAY_SERVICENAME = cfg.relay.serviceName; RELAY_DOMAIN = cfg.relay.domain; RELAY_SUMMARY = cfg.relay.summary; JOB_CONCURRENCY = cfg.jobConcurrency; } // lib.optionalAttrs (cfg.relay.icon != null) { RELAY_ICON = cfg.relay.icon; } // lib.optionalAttrs (cfg.relay.image != null) { RELAY_IMAGE = cfg.relay.image; })); in { options.services.activity-relay = { enable = lib.mkEnableOption "Activity-Relay ActivityPub relay server"; package = lib.mkOption { type = lib.types.package; default = pkgs.activity-relay; }; user = lib.mkOption { type = lib.types.str; default = "relay"; }; group = lib.mkOption { type = lib.types.str; default = "relay"; }; actorPem.path = lib.mkOption { type = lib.types.str; default = "${config.users.users.${cfg.user}.home}/actor.pem"; }; actorPem.generate = lib.mkOption { type = lib.types.bool; default = true; }; redisUrl = lib.mkOption { type = lib.types.str; default = "redis://127.0.0.1:6379"; }; relay = { bind = lib.mkOption { type = lib.types.str; default = "0.0.0.0:8080"; }; domain = lib.mkOption { type = lib.types.str; }; serviceName = lib.mkOption { type = lib.types.str; default = "NixOS Activity-Relay"; }; summary = lib.mkOption { type = lib.types.str; default = ""; }; icon = lib.mkOption { type = with lib.types; nullOr str; default = null; }; image = lib.mkOption { type = with lib.types; nullOr str; default = null; }; }; jobConcurrency = lib.mkOption { type = lib.types.int; default = 50; }; }; config = lib.mkIf cfg.enable { users = { users.${cfg.user} = { isSystemUser = true; inherit (cfg) group; home = "/var/lib/activity-relay"; }; groups.${cfg.group} = {}; }; systemd.services = { relay-api = { description = "Activity-Relay server"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { User = cfg.user; Group = cfg.group; StateDirectory = "activity-relay"; CapabilityBoundingSet = ""; PrivateDevices = true; PrivateUsers = true; ProtectHome = true; ProtectKernelLogs = true; ProtectProc = "invisible"; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; RestrictNamespaces = true; SystemCallArchitectures = "native"; # SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; Restart = lib.mkDefault "always"; RestartSec = 10; }; script = '' ${lib.optionalString cfg.actorPem.generate '' if ! [ -e "${cfg.actorPem.path}" ]; then ${lib.getExe pkgs.openssl} genrsa -traditional > "${cfg.actorPem.path}" fi ''} exec ${lib.getExe cfg.package} -c ${configFile} -v server ''; }; relay-worker = { description = "Activity-Relay worker"; after = [ "network.target" "relay-api.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { User = cfg.user; Group = cfg.group; StateDirectory = "activity-relay"; CapabilityBoundingSet = ""; PrivateDevices = true; PrivateUsers = true; ProtectHome = true; ProtectKernelLogs = true; ProtectProc = "invisible"; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; RestrictNamespaces = true; SystemCallArchitectures = "native"; # SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; Restart = lib.mkDefault "always"; RestartSec = 10; ExecStart = "${lib.getExe cfg.package} -c ${configFile} -v worker"; }; }; }; }; }