diff --git a/nixos/doc/manual/release-notes/rl-2511.section.md b/nixos/doc/manual/release-notes/rl-2511.section.md index 150cee196967..f9a0ef68873b 100644 --- a/nixos/doc/manual/release-notes/rl-2511.section.md +++ b/nixos/doc/manual/release-notes/rl-2511.section.md @@ -98,6 +98,8 @@ - [fw-fanctrl](https://github.com/TamtamHero/fw-fanctrl), a simple systemd service to better control Framework Laptop's fan(s). Available as [hardware.fw-fanctrl](#opt-hardware.fw-fanctrl.enable). +- [SillyTavern](https://sillytavern.app/), LLM Frontend for Power Users. Available as [services.sillytavern](#opt-services.sillytavern.enable). + - [mautrix-discord](https://github.com/mautrix/discord), a Matrix-Discord puppeting/relay bridge. Available as [services.mautrix-discord](#opt-services.mautrix-discord.enable). - [Timekpr-nExT](https://mjasnik.gitlab.io/timekpr-next/), a time managing application that helps optimizing time spent at computer for your subordinates, children or even for yourself. Available as [](#opt-services.timekpr.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 42147814225b..7e024f6113c5 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1688,6 +1688,7 @@ ./services/web-apps/sftpgo.nix ./services/web-apps/sharkey.nix ./services/web-apps/shiori.nix + ./services/web-apps/sillytavern.nix ./services/web-apps/silverbullet.nix ./services/web-apps/simplesamlphp.nix ./services/web-apps/slskd.nix diff --git a/nixos/modules/services/web-apps/sillytavern.nix b/nixos/modules/services/web-apps/sillytavern.nix new file mode 100644 index 000000000000..8983eca8055a --- /dev/null +++ b/nixos/modules/services/web-apps/sillytavern.nix @@ -0,0 +1,170 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.sillytavern; + defaultUser = "sillytavern"; + defaultGroup = "sillytavern"; +in +{ + meta.maintainers = [ + lib.maintainers.wrvsrx + lib.maintainers.A1ca7raz + ]; + + options = { + services.sillytavern = { + enable = lib.mkEnableOption "sillytavern"; + + user = lib.mkOption { + type = lib.types.str; + default = defaultUser; + description = '' + User account under which the web-application run. + ''; + }; + group = lib.mkOption { + type = lib.types.str; + default = defaultGroup; + description = '' + Group account under which the web-application run. + ''; + }; + + package = lib.mkPackageOption pkgs "sillytavern" { }; + + configFile = lib.mkOption { + type = lib.types.path; + default = "${pkgs.sillytavern}/lib/node_modules/sillytavern/config.yaml"; + defaultText = lib.literalExpression "\${pkgs.sillytavern}/lib/node_modules/sillytavern/config.yaml"; + description = '' + Path to the SillyTavern configuration file. + ''; + }; + + port = lib.mkOption { + type = lib.types.nullOr lib.types.port; + default = null; + example = 8045; + description = '' + Port on which SillyTavern will listen. + ''; + }; + + listenAddressIPv4 = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "127.0.0.1"; + description = '' + Specific IPv4 address to listen to. + ''; + }; + + listenAddressIPv6 = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "::1"; + description = '' + Specific IPv6 address to listen to. + ''; + }; + + listen = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = '' + Whether to listen on all network interfaces. + ''; + }; + + whitelist = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = '' + Enables whitelist mode. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.sillytavern = { + description = "Silly Tavern"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + # required by sillytavern's extension manager + path = [ pkgs.git ]; + environment.XDG_DATA_HOME = "%S"; + serviceConfig = { + Type = "simple"; + ExecStart = + let + f = x: name: lib.optional (x != null) "--${name}=${builtins.toString x}"; + in + lib.concatStringsSep " " ( + [ + "${lib.getExe pkgs.sillytavern}" + ] + ++ f cfg.port "port" + ++ f cfg.listen "listen" + ++ f cfg.listenAddressIPv4 "listenAddressIPv4" + ++ f cfg.listenAddressIPv6 "listenAddressIPv6" + ++ f cfg.whitelist "whitelist" + ); + User = cfg.user; + Group = cfg.group; + Restart = "always"; + StateDirectory = "SillyTavern"; + BindPaths = [ + "%S/SillyTavern/extensions:${pkgs.sillytavern}/lib/node_modules/sillytavern/public/scripts/extensions/third-party" + ]; + + # Security hardening + CapabilityBoundingSet = [ "" ]; + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + }; + }; + + users.users.${cfg.user} = lib.mkIf (cfg.user == defaultUser) { + description = "sillytavern service user"; + isSystemUser = true; + inherit (cfg) group; + }; + + users.groups.${cfg.group} = lib.mkIf (cfg.group == defaultGroup) { }; + + systemd.tmpfiles.settings.sillytavern = { + "/var/lib/SillyTavern/data".d = { + mode = "0700"; + inherit (cfg) user group; + }; + "/var/lib/SillyTavern/extensions".d = { + mode = "0700"; + inherit (cfg) user group; + }; + "/var/lib/SillyTavern/config.yaml"."L+" = { + mode = "0600"; + argument = cfg.configFile; + inherit (cfg) user group; + }; + }; + }; +}