{ options, config, pkgs, lib, ... }: with lib; let cfg = config.services.gotosocial; settingsFormat = pkgs.formats.json {}; in { options = { services.gotosocial = with lib; { enable = mkEnableOption "GoToSocial ActivityPub Server"; package = mkOption { type = types.package; default = pkgs.gotosocial; }; user = mkOption { type = types.str; default = "gotosocial"; }; group = mkOption { type = types.str; default = "gotosocial"; }; stateDir = mkOption { type = types.str; default = "/var/lib/gotosocial"; readOnly = true; }; settings = lib.mkOption { type = lib.types.submodule { freeformType = settingsFormat.type; options.host = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; description = '' Hostname that this server will be reachable at. Defaults to localhost for local testing, but you should *definitely* change this when running for real, or your server won't work at all. DO NOT change this after your server has already run once, or you will break things! ''; }; options.port = lib.mkOption { type = lib.types.port; default = 8080; description = '' Int. Listen port for the GoToSocial webserver + API. If you're running behind a reverse proxy and/or in a docker, container, just set this to whatever you like (or leave the default), and make sure it's forwarded properly. If you are running with built-in letsencrypt enabled, and running GoToSocial directly on a host machine, you will probably want to set this to 443 (standard https port), unless you have other services already using that port. This *MUST NOT* be the same as the letsencrypt port specified below, unless letsencrypt is turned off. ''; }; }; default = {}; description = '' Configuration for GoToSocial, see for supported values. ''; }; }; }; config = lib.mkIf cfg.enable (let configFile = settingsFormat.generate "gotosocial-config.yaml" cfg.settings; in { assertions = [ { assertion = cfg.settings.host != null; message = "You have to define a hostname for GoToSocial, it cannot be changed later without starting over!"; } ]; services.gotosocial.settings = { # Defaults user = lib.mkDefault "gotosocial"; group = lib.mkDefault "gotosocial"; storage-local-base-path = lib.mkDefault "/var/lib/gotosocial"; # SystemD StateDirectory web-template-base-dir = lib.mkDefault "${cfg.package}/share/web/template/"; web-asset-base-dir = lib.mkDefault "${cfg.package}/share/web/assets/"; }; users = { users."${cfg.user}" = { home = cfg.stateDir; group = cfg.group; isSystemUser = true; }; groups."${cfg.group}" = {}; }; environment.etc."gotosocial.yaml".source = configFile; environment.systemPackages = [ (pkgs.writeShellScriptBin "gotosocial" '' exec ${cfg.package}/bin/gotosocial --config-path ${configFile} "$@" '') ]; systemd.services = { gotosocial = { description = "GoToSocial ActivityPub Server"; after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; onFailure = [ "email-notify@%i.service" ]; serviceConfig = { User = cfg.user; Group = cfg.group; Type = "exec"; WorkingDirectory = "~"; StateDirectory = lib.mkIf (cfg.settings.storage-local-base-path != "/var/lib/gotosocial") "gotosocial"; ReadOnlyPaths = [ cfg.package ]; ReadWritePaths = [ cfg.settings.storage-local-base-path ]; StateDirectoryMode = "750"; Restart = "always"; RestartSec = 3; ExecStart = "${cfg.package}/bin/gotosocial --config-path ${configFile} server start"; NoNewPrivileges = true; PrivateTmp = true; PrivateDevices = false; RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6"; RestrictNamespaces = true; RestrictRealtime = true; ProtectSystem = "full"; ProtectControlGroups = true; ProtectKernelModules = true; ProtectKernelTunables = true; DevicePolicy = "closed"; LockPersonality = true; SystemCallFilter = "~@clock @debug @module @mount @obsolete @reboot @setuid @swap"; CapabilityBoundingSet = [ "~CAP_RAWIO CAP_MKNOD" "~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE" "~CAP_SYS_BOOT CAP_SYS_TIME CAP_SYS_MODULE CAP_SYS_PACCT" "~CAP_LEASE CAP_LINUX_IMMUTABLE CAP_IPC_LOCK" "~CAP_BLOCK_SUSPEND CAP_WAKE_ALARM" "~CAP_SYS_TTY_CONFIG" "~CAP_MAC_ADMIN CAP_MAC_OVERRIDE" "~CAP_NET_ADMIN CAP_NET_BROADCAST CAP_NET_RAW" "~CAP_SYS_ADMIN CAP_SYS_PTRACE CAP_SYSLOG" ]; }; }; }; }); }