nixpkgs/nixos/modules/services/web-apps/libretranslate.nix
2025-10-21 21:01:38 +02:00

234 lines
6.4 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.libretranslate;
ltmanageKeysCli = pkgs.writeShellScriptBin "ltmanage-keys" ''
set -a
export HOME="/var/lib/libretranslate"
sudo=exec
if [[ "$USER" != ${cfg.user} ]]; then
sudo='exec /run/wrappers/bin/sudo -u ${cfg.user} --preserve-env'
fi
$sudo ${cfg.package}/bin/ltmanage keys --api-keys-db-path ${cfg.dataDir}/db/api_keys.db "$@"
'';
in
{
options = {
services.libretranslate = {
enable = lib.mkEnableOption "LibreTranslate service";
package = lib.mkPackageOption pkgs "libretranslate" { };
user = lib.mkOption {
type = lib.types.str;
default = "libretranslate";
description = "User account under which libretranslate runs.";
};
group = lib.mkOption {
type = lib.types.str;
default = "libretranslate";
description = "Group account under which libretranslate runs.";
};
host = lib.mkOption {
description = "The address the application should listen on.";
type = lib.types.str;
default = "127.0.0.1";
};
port = lib.mkOption {
type = lib.types.port;
default = 5000;
description = "The the application should listen on.";
};
dataDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/libretranslate";
example = "/srv/data/libretranslate";
description = "The data directory.";
};
threads = lib.mkOption {
type = lib.types.nullOr lib.types.ints.positive;
default = null;
example = 8;
description = "Set number of threads.";
};
enableApiKeys = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = "Whether to enable the API keys database.";
};
disableWebUI = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = "Whether to disable the Web UI.";
};
updateModels = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = "Update language models at startup";
};
domain = lib.mkOption {
type = lib.types.str;
default = "";
example = "libretranslate.example.com";
description = ''
The domain serving your LibreTranslate instance.
Required for configure nginx as a reverse proxy.
'';
};
configureNginx = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Configure nginx as a reverse proxy for LibreTranslate.";
};
extraArgs = lib.mkOption {
type =
with lib.types;
attrsOf (
nullOr (oneOf [
bool
str
int
(listOf (oneOf [
bool
str
int
]))
])
);
default = { };
example = {
debug = true;
disable-files-translation = true;
url-prefix = "translate";
};
description = "Extra arguments passed to the LibreTranslate.";
};
};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = lib.mkIf cfg.enableApiKeys [ ltmanageKeysCli ];
systemd.tmpfiles.rules = lib.mkIf (cfg.dataDir != "/var/lib/libretranslate") [
"d '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.group} - -"
"z '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.group} - -"
];
systemd.services.libretranslate = {
description = "LibreTranslate service";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
HOME = cfg.dataDir;
};
serviceConfig = lib.mkMerge [
{
Type = "simple";
ExecStart = ''
${cfg.package}/bin/libretranslate ${
lib.cli.toCommandLineShellGNU { } (
cfg.extraArgs
// {
inherit (cfg) host port threads;
api-keys = cfg.enableApiKeys;
disable-web-ui = cfg.disableWebUI;
update-models = cfg.updateModels;
}
)
}
'';
WorkingDirectory = cfg.dataDir;
User = cfg.user;
Group = cfg.group;
ProcSubset = "all";
ProtectProc = "invisible";
UMask = "0027";
CapabilityBoundingSet = "";
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = false;
RestrictRealtime = true;
RestrictSUIDSGID = true;
RemoveIPC = true;
PrivateMounts = true;
SystemCallArchitectures = "native";
SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid" ];
}
(lib.mkIf (cfg.dataDir == "/var/lib/libretranslate") {
StateDirectory = "libretranslate";
StateDirectoryMode = "0750";
})
(lib.mkIf (cfg.dataDir != "/var/lib/libretranslate") {
ReadWritePaths = cfg.dataDir;
})
];
};
services.nginx = lib.mkIf cfg.configureNginx {
enable = true;
virtualHosts."${cfg.domain}" = {
root = "/var/empty";
locations."/" = {
proxyPass = "http://127.0.0.1:${toString cfg.port}";
};
locations."= /favicon.ico" = {
alias = "${cfg.package.static-compressed}/share/libretranslate/static/favicon.ico";
};
locations."^~ /static/" = {
alias = "${cfg.package.static-compressed}/share/libretranslate/static/";
};
};
};
users.users = lib.optionalAttrs (cfg.user == "libretranslate") {
libretranslate = {
group = cfg.group;
isSystemUser = true;
};
};
users.groups = lib.optionalAttrs (cfg.group == "libretranslate") {
libretranslate = { };
};
};
}