nixpkgs/nixos/modules/services/web-apps/sillytavern.nix
2025-09-10 00:14:50 +08:00

171 lines
4.5 KiB
Nix

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