Unverified Commit cbec672b authored by Izorkin's avatar Izorkin Committed by Sandro Jäckel
Browse files

nixos/libretranslate: init

parent c944da85
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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
+233 −0
Original line number Diff line number Diff line
{
  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 = { };
    };
  };
}