From 8da52ebb52a76a074de4665315ea5f92882e5c6d Mon Sep 17 00:00:00 2001 From: Philipp Date: Sat, 31 May 2025 14:17:45 +0200 Subject: [PATCH] feature(ente): add ente-api to module --- modules/nixos/services/ente-auth/default.nix | 283 ++++++++++++++++--- packages/ente-web-auth/default.nix | 1 - systems/x86_64-linux/blarm/default.nix | 5 +- 3 files changed, 250 insertions(+), 39 deletions(-) diff --git a/modules/nixos/services/ente-auth/default.nix b/modules/nixos/services/ente-auth/default.nix index a0b192e..16b6b05 100644 --- a/modules/nixos/services/ente-auth/default.nix +++ b/modules/nixos/services/ente-auth/default.nix @@ -1,59 +1,268 @@ { - lib, - pkgs, - config, - namespace, - ... +lib, +pkgs, +config, +namespace, +... }: with lib; with lib.${namespace}; let - cfg = config.${namespace}.services.ente-auth; + cfg = config.${namespace}.services.ente; + cfgWeb = cfg.web; + cfgApi = cfg.api; + + defaultUser = "ente"; + defaultGroup = "ente"; + dataDir = "/var/lib/ente"; + + yamlFormat = pkgs.formats.yaml { }; + + enteApp = + cfgWeb.package.override { + extraBuildEnv = { + NEXT_PUBLIC_ENTE_ENDPOINT = "https://ente-api.monapona.dev"; + NEXT_TELEMETRY_DISABLED = "1"; + }; + }; in -{ - options.${namespace}.services.ente-auth = { - enable = mkEnableOption "Ente-Auth"; - - package = mkOption { - description = "The package of Ente-Auth to use."; - type = types.package; - default = pkgs.awesome-flake.ente-web-auth; - }; - - domain = mkOption { - description = "The domain to serve ente-auth on."; - type = types.nullOr types.str; - default = "ente.stahl.sh"; - }; - + { + options.${namespace}.services.ente = { nginx = { enable = mkEnableOption "Enable nginx for this service." - // { + // { default = true; + }; + }; + + web = { + enable = mkEnableOption "Ente-Auth-Web"; + + package = mkOption { + description = "The package of Ente-Auth to use."; + type = types.package; + default = pkgs.awesome-flake.ente-web-auth; + }; + + domain = mkOption { + description = "The domain to serve ente-auth on."; + type = types.nullOr types.str; + default = "ente.stahl.sh"; }; }; - }; + api = { + enable = mkEnableOption "Ente-API"; - config = mkIf cfg.enable { - networking.firewall.allowedTCPPorts = mkIf cfg.nginx.enable [ - 80 - 443 - ]; + package = mkOption { + description = "The package of Ente-API to use."; + type = types.package; + default = pkgs.museum; + }; - awesome-flake.services.acme.enable = mkIf cfg.nginx.enable true; + user = mkOption { + type = types.str; + default = defaultUser; + description = "User under which museum runs."; + }; - services.nginx = mkIf cfg.nginx.enable { - enable = true; + group = mkOption { + type = types.str; + default = defaultGroup; + description = "Group under which museum runs."; + }; - virtualHosts."${cfg.domain}" = { - forceSSL = true; - useACMEHost = "stahl.sh"; - locations."/" = { - root = "${cfg.package}"; + domain = mkOption { + description = "The domain to serve the API on."; + type = types.nullOr types.str; + default = "ente-api.stahl.sh"; + }; + + enableLocalDB = mkEnableOption "the automatic creation of a local postgres database for museum."; + + settings = mkOption { + description = '' + Museum yaml configuration. Refer to upstream [local.yaml](https://github.com/ente-io/ente/blob/main/server/configurations/local.yaml) for more information. + You can specify secret values in this configuration by setting `somevalue._secret = "/path/to/file"` instead of setting `somevalue` directly. + ''; + default = { }; + type = types.submodule { + freeformType = yamlFormat.type; + options = { + db = { + host = mkOption { + type = types.str; + default = "/run/postgresql"; + description = "The database host"; + }; + + port = mkOption { + type = types.port; + default = 5432; + description = "The database port"; + }; + + name = mkOption { + type = types.str; + default = "ente"; + description = "The database name"; + }; + + user = mkOption { + type = types.str; + default = "ente"; + description = "The database user"; + }; + }; + }; }; }; }; }; + config = mkMerge [ + (mkIf cfgApi.enable { + services.postgresql = mkIf cfgApi.enableLocalDB { + enable = true; + ensureUsers = [ + { + name = "ente"; + ensureDBOwnership = true; + } + ]; + ensureDatabases = [ "ente" ]; + }; + + ${namespace}.services.ente.api.settings = { + log-file = mkDefault ""; + db = mkIf cfgApi.enableLocalDB { + host = "/run/postgresql"; + port = 5432; + name = "ente"; + user = "ente"; + }; + }; + + systemd.services.ente = { + description = "Ente.io Museum API Server"; + after = [ "network.target" ] ++ optional cfgApi.enableLocalDB "postgresql.service"; + requires = optional cfgApi.enableLocalDB "postgresql.service"; + wantedBy = [ "multi-user.target" ]; + + preStart = '' + # Setup paths + mkdir -p ${dataDir}/configurations + cp ${yamlFormat.generate "local.yaml" cfgApi.settings} ${dataDir}/configurations/local.yml + ''; + + serviceConfig = { + ExecStart = getExe cfgApi.package; + Type = "simple"; + Restart = "on-failure"; + + AmbientCapablities = [ ]; + CapabilityBoundingSet = [ ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateMounts = true; + PrivateTmp = true; + PrivateUsers = false; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_NETLINK" + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "@system-service"; + UMask = "077"; + + BindReadOnlyPaths = [ + "${cfgApi.package}/share/museum/migrations:${dataDir}/migrations" + "${cfgApi.package}/share/museum/mail-templates:${dataDir}/mail-templates" + ]; + + User = cfgApi.user; + Group = cfgApi.group; + + SyslogIdentifier = "ente"; + StateDirectory = "ente"; + WorkingDirectory = dataDir; + RuntimeDirectory = "ente"; + }; + + # Environment MUST be called local, otherwise we cannot log to stdout + environment = { + ENVIRONMENT = "local"; + GIN_MODE = "release"; + }; + }; + + users = { + users = mkIf (cfgApi.user == defaultUser) { + ${defaultUser} = { + description = "ente.io museum service user"; + inherit (cfgApi) group; + isSystemUser = true; + home = dataDir; + }; + }; + groups = mkIf (cfgApi.group == defaultGroup) { ${defaultGroup} = { }; }; + }; + + services.nginx = mkIf cfg.nginx.enable { + enable = true; + upstreams.museum = { + servers."localhost:8080" = { }; + extraConfig = '' + zone museum 64k; + keepalive 20; + ''; + }; + + virtualHosts.${cfgApi.domain} = { + forceSSL = true; + useACMEHost = "stahl.sh"; + locations."/".proxyPass = "http://museum"; + extraConfig = '' + client_max_body_size 4M; + ''; + }; + }; + }) + + (mkIf cfgWeb.enable { + networking.firewall.allowedTCPPorts = mkIf cfg.nginx.enable [ + 80 + 443 + ]; + + awesome-flake.services.acme.enable = mkIf cfg.nginx.enable true; + + services.nginx = mkIf cfg.nginx.enable { + enable = true; + + virtualHosts."${cfgWeb.domain}" = { + forceSSL = true; + useACMEHost = "stahl.sh"; + locations."/".root = enteApp; + }; + }; + }) + ]; + } diff --git a/packages/ente-web-auth/default.nix b/packages/ente-web-auth/default.nix index cd3451d..6108b43 100644 --- a/packages/ente-web-auth/default.nix +++ b/packages/ente-web-auth/default.nix @@ -39,7 +39,6 @@ stdenv.mkDerivation (finalAttrs: { env = extraBuildEnv; buildPhase = '' - export NEXT_PUBLIC_ENTE_ENDPOINT=https://ente-api.monapona.dev yarn build:auth ''; diff --git a/systems/x86_64-linux/blarm/default.nix b/systems/x86_64-linux/blarm/default.nix index 7bca4a4..f65f5fa 100644 --- a/systems/x86_64-linux/blarm/default.nix +++ b/systems/x86_64-linux/blarm/default.nix @@ -54,12 +54,15 @@ with lib.${namespace}; services = { ssh = enabled; cinny = enabled; - ente-auth = enabled; restic = enabled; linkwarden = enabled; forgejo = enabled; searxng = enabled; immich = enabled; + ente = { + api = enabled; + web = enabled; + }; }; #container.invidious = enabled;