nixos/libretranslate: init (#243050)

This commit is contained in:
Sandro
2025-07-27 04:44:01 +02:00
committed by GitHub
4 changed files with 261 additions and 1 deletions
@@ -34,7 +34,9 @@
- Auto-scrub support for Bcachefs filesystems can now be enabled through [services.bcachefs.autoScrub.enable](#opt-services.bcachefs.autoScrub.enable) to periodically check for data corruption. If there's a correct copy available, it will automatically repair corrupted blocks.
- [tlsrpt-reporter], an application suite to generate and deliver TLSRPT reports. Available as [services.tlsrpt](#opt-services.tlsrpt.enable).
- [LibreTranslate](https://libretranslate.com), a free and open source machine translation API. Available as [services.libretranslate](#opt-services.libretranslate.enable).
- [tlsrpt-reporter](https://github.com/sys4/tlsrpt-reporter), an application suite to generate and deliver TLSRPT reports. Available as [services.tlsrpt](#opt-services.tlsrpt.enable).
- [Chhoto URL](https://github.com/SinTan1729/chhoto-url), a simple, blazingly fast, selfhosted URL shortener with no unnecessary features, written in Rust. Available as [services.chhoto-url](#opt-services.chhoto-url.enable).
+1
View File
@@ -1611,6 +1611,7 @@
./services/web-apps/lasuite-docs.nix
./services/web-apps/lasuite-meet.nix
./services/web-apps/lemmy.nix
./services/web-apps/libretranslate.nix
./services/web-apps/limesurvey.nix
./services/web-apps/mainsail.nix
./services/web-apps/mastodon.nix
@@ -0,0 +1,233 @@
{
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.toGNUCommandLineShell { } (
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 = { };
};
};
}
@@ -1,8 +1,10 @@
{
lib,
pkgs,
buildPythonPackage,
fetchFromGitHub,
pytestCheckHook,
runCommand,
hatchling,
argostranslate,
flask,
@@ -15,6 +17,7 @@
expiringdict,
langdetect,
lexilang,
libretranslate,
ltpycld2,
morfessor,
appdirs,
@@ -26,6 +29,7 @@
prometheus-client,
polib,
python,
xorg,
}:
buildPythonPackage rec {
@@ -85,6 +89,26 @@ buildPythonPackage rec {
pythonImportsCheck = [ "libretranslate" ];
passthru = {
static-compressed =
runCommand "libretranslate-data-compressed"
{
nativeBuildInputs = [
pkgs.brotli
xorg.lndir
];
}
''
mkdir -p $out/share/libretranslate/static
lndir ${libretranslate}/share/libretranslate/static $out/share/libretranslate/static
# Create static gzip and brotli files
find -L $out -type f -regextype posix-extended -iregex '.*\.(css|ico|js|svg|ttf)' \
-exec gzip --best --keep --force {} ';' \
-exec brotli --best --keep --no-copy-stat {} ';'
'';
};
meta = with lib; {
description = "Free and Open Source Machine Translation API. Self-hosted, no limits, no ties to proprietary services";
homepage = "https://libretranslate.com";