at master 6.6 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.services.libretranslate; 10 ltmanageKeysCli = pkgs.writeShellScriptBin "ltmanage-keys" '' 11 set -a 12 export HOME="/var/lib/libretranslate" 13 sudo=exec 14 if [[ "$USER" != ${cfg.user} ]]; then 15 sudo='exec /run/wrappers/bin/sudo -u ${cfg.user} --preserve-env' 16 fi 17 $sudo ${cfg.package}/bin/ltmanage keys --api-keys-db-path ${cfg.dataDir}/db/api_keys.db "$@" 18 ''; 19 20in 21{ 22 options = { 23 services.libretranslate = { 24 enable = lib.mkEnableOption "LibreTranslate service"; 25 26 package = lib.mkPackageOption pkgs "libretranslate" { }; 27 28 user = lib.mkOption { 29 type = lib.types.str; 30 default = "libretranslate"; 31 description = "User account under which libretranslate runs."; 32 }; 33 34 group = lib.mkOption { 35 type = lib.types.str; 36 default = "libretranslate"; 37 description = "Group account under which libretranslate runs."; 38 }; 39 40 host = lib.mkOption { 41 description = "The address the application should listen on."; 42 type = lib.types.str; 43 default = "127.0.0.1"; 44 }; 45 46 port = lib.mkOption { 47 type = lib.types.port; 48 default = 5000; 49 description = "The the application should listen on."; 50 }; 51 52 dataDir = lib.mkOption { 53 type = lib.types.path; 54 default = "/var/lib/libretranslate"; 55 example = "/srv/data/libretranslate"; 56 description = "The data directory."; 57 }; 58 59 threads = lib.mkOption { 60 type = lib.types.nullOr lib.types.ints.positive; 61 default = null; 62 example = 8; 63 description = "Set number of threads."; 64 }; 65 66 enableApiKeys = lib.mkOption { 67 type = lib.types.bool; 68 default = false; 69 example = true; 70 description = "Whether to enable the API keys database."; 71 }; 72 73 disableWebUI = lib.mkOption { 74 type = lib.types.bool; 75 default = false; 76 example = true; 77 description = "Whether to disable the Web UI."; 78 }; 79 80 updateModels = lib.mkOption { 81 type = lib.types.bool; 82 default = false; 83 example = true; 84 description = "Update language models at startup"; 85 }; 86 87 domain = lib.mkOption { 88 type = lib.types.str; 89 default = ""; 90 example = "libretranslate.example.com"; 91 description = '' 92 The domain serving your LibreTranslate instance. 93 Required for configure nginx as a reverse proxy. 94 ''; 95 }; 96 97 configureNginx = lib.mkOption { 98 type = lib.types.bool; 99 default = false; 100 description = "Configure nginx as a reverse proxy for LibreTranslate."; 101 }; 102 103 extraArgs = lib.mkOption { 104 type = 105 with lib.types; 106 attrsOf ( 107 nullOr (oneOf [ 108 bool 109 str 110 int 111 (listOf (oneOf [ 112 bool 113 str 114 int 115 ])) 116 ]) 117 ); 118 default = { }; 119 example = { 120 debug = true; 121 disable-files-translation = true; 122 url-prefix = "translate"; 123 }; 124 description = "Extra arguments passed to the LibreTranslate."; 125 }; 126 }; 127 }; 128 129 config = lib.mkIf cfg.enable { 130 environment.systemPackages = lib.mkIf cfg.enableApiKeys [ ltmanageKeysCli ]; 131 132 systemd.tmpfiles.rules = lib.mkIf (cfg.dataDir != "/var/lib/libretranslate") [ 133 "d '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.group} - -" 134 "z '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.group} - -" 135 ]; 136 137 systemd.services.libretranslate = { 138 description = "LibreTranslate service"; 139 after = [ "network.target" ]; 140 wantedBy = [ "multi-user.target" ]; 141 environment = { 142 HOME = cfg.dataDir; 143 }; 144 serviceConfig = lib.mkMerge [ 145 { 146 Type = "simple"; 147 ExecStart = '' 148 ${cfg.package}/bin/libretranslate ${ 149 lib.cli.toGNUCommandLineShell { } ( 150 cfg.extraArgs 151 // { 152 inherit (cfg) host port threads; 153 api-keys = cfg.enableApiKeys; 154 disable-web-ui = cfg.disableWebUI; 155 update-models = cfg.updateModels; 156 } 157 ) 158 } 159 ''; 160 WorkingDirectory = cfg.dataDir; 161 User = cfg.user; 162 Group = cfg.group; 163 ProcSubset = "all"; 164 ProtectProc = "invisible"; 165 UMask = "0027"; 166 CapabilityBoundingSet = ""; 167 NoNewPrivileges = true; 168 ProtectSystem = "strict"; 169 ProtectHome = true; 170 PrivateTmp = true; 171 PrivateDevices = true; 172 PrivateUsers = true; 173 ProtectHostname = true; 174 ProtectClock = true; 175 ProtectKernelTunables = true; 176 ProtectKernelModules = true; 177 ProtectKernelLogs = true; 178 ProtectControlGroups = true; 179 RestrictAddressFamilies = [ 180 "AF_INET" 181 "AF_INET6" 182 ]; 183 RestrictNamespaces = true; 184 LockPersonality = true; 185 MemoryDenyWriteExecute = false; 186 RestrictRealtime = true; 187 RestrictSUIDSGID = true; 188 RemoveIPC = true; 189 PrivateMounts = true; 190 SystemCallArchitectures = "native"; 191 SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid" ]; 192 } 193 (lib.mkIf (cfg.dataDir == "/var/lib/libretranslate") { 194 StateDirectory = "libretranslate"; 195 StateDirectoryMode = "0750"; 196 }) 197 (lib.mkIf (cfg.dataDir != "/var/lib/libretranslate") { 198 ReadWritePaths = cfg.dataDir; 199 }) 200 ]; 201 }; 202 203 services.nginx = lib.mkIf cfg.configureNginx { 204 enable = true; 205 virtualHosts."${cfg.domain}" = { 206 root = "/var/empty"; 207 208 locations."/" = { 209 proxyPass = "http://127.0.0.1:${toString cfg.port}"; 210 }; 211 212 locations."= /favicon.ico" = { 213 alias = "${cfg.package.static-compressed}/share/libretranslate/static/favicon.ico"; 214 }; 215 216 locations."^~ /static/" = { 217 alias = "${cfg.package.static-compressed}/share/libretranslate/static/"; 218 }; 219 }; 220 }; 221 222 users.users = lib.optionalAttrs (cfg.user == "libretranslate") { 223 libretranslate = { 224 group = cfg.group; 225 isSystemUser = true; 226 }; 227 }; 228 229 users.groups = lib.optionalAttrs (cfg.group == "libretranslate") { 230 libretranslate = { }; 231 }; 232 }; 233}