diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index 9e88cfa3c165..828801264652 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -19399,6 +19399,11 @@ githubId = 79978224; name = "winston"; }; + nelind = { + name = "Nel"; + github = "nelind3"; + githubId = 57587152; + }; nelsonjeppesen = { email = "nix@jeppesen.io"; github = "NelsonJeppesen"; diff --git a/nixos/doc/manual/release-notes/rl-2611.section.md b/nixos/doc/manual/release-notes/rl-2611.section.md index 17f5f67082f9..f029f3e9032f 100644 --- a/nixos/doc/manual/release-notes/rl-2611.section.md +++ b/nixos/doc/manual/release-notes/rl-2611.section.md @@ -10,7 +10,7 @@ -- Create the first release note entry in this section! +- [tranquil](https://tangled.org/tranquil.farm/tranquil-pds) is an ATProto PDS (personal data server) implementation in Rust. A featureful, spec conscious and community driven alternative to the Bluesky reference implementation PDS. Available as [services.tranquil-pds](#opt-services.tranquil-pds.enable). ## Backward Incompatibilities {#sec-release-26.11-incompatibilities} diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index cb6dbf5b41bd..dc047426c0ca 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1793,6 +1793,7 @@ ./services/web-apps/suwayomi-server.nix ./services/web-apps/szurubooru.nix ./services/web-apps/tabbyapi.nix + ./services/web-apps/tranquil-pds.nix ./services/web-apps/trilium.nix ./services/web-apps/tt-rss.nix ./services/web-apps/tuliprox.nix diff --git a/nixos/modules/services/web-apps/tranquil-pds.nix b/nixos/modules/services/web-apps/tranquil-pds.nix new file mode 100644 index 000000000000..b3a5b2fb6fdc --- /dev/null +++ b/nixos/modules/services/web-apps/tranquil-pds.nix @@ -0,0 +1,251 @@ +{ + lib, + pkgs, + config, + ... +}: +let + cfg = config.services.tranquil-pds; + + inherit (lib) types mkPackageOption mkOption; + + settingsFormat = pkgs.formats.toml { }; +in +{ + options.services.tranquil-pds = { + enable = lib.mkEnableOption "tranquil-pds AT Protocol personal data server"; + + package = mkPackageOption pkgs "tranquil-pds" { }; + + user = mkOption { + type = types.str; + default = "tranquil-pds"; + description = "User under which tranquil-pds runs"; + }; + + group = mkOption { + type = types.str; + default = "tranquil-pds"; + description = "Group under which tranquil-pds runs"; + }; + + dataDir = mkOption { + type = types.str; + default = "/var/lib/tranquil-pds"; + description = "Working directory for tranquil-pds. Also expected to be used for data (blobs)"; + }; + + environmentFiles = mkOption { + type = types.listOf types.path; + default = [ ]; + description = '' + File to load environment variables from. Loaded variables override + values set in {option}`environment`. + + Use it to set values of `JWT_SECRET`, `DPOP_SECRET` and `MASTER_KEY`. + + Generate these with: + ``` + openssl rand -base64 48 + ``` + ''; + }; + + database.createLocally = mkOption { + type = types.bool; + default = false; + description = '' + Create the postgres database and user on the local host. + ''; + }; + + settings = mkOption { + type = types.submodule { + freeformType = settingsFormat.type; + + options = { + server = { + host = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "Host for tranquil-pds to listen on"; + }; + + port = mkOption { + type = types.int; + default = 3000; + description = "Port for tranquil-pds to listen on"; + }; + + hostname = mkOption { + type = types.str; + default = ""; + example = "pds.example.com"; + description = "The public-facing hostname of the PDS"; + }; + + max_blob_size = mkOption { + type = types.int; + default = 10737418240; # 10 GiB + description = "Maximum allowed blob size in bytes."; + }; + }; + + frontend = { + enabled = + lib.mkEnableOption "serving the frontend from the backend. Disable to serve the frontend manually" + // { + default = true; + }; + + dir = mkPackageOption pkgs "tranquil-pds-frontend" { }; + }; + + storage = { + path = mkOption { + type = types.path; + default = "${cfg.dataDir}/blobs"; + defaultText = "\${cfg.dataDir}/blobs"; + description = "Directory for storing blobs"; + }; + }; + tranquil_store = { + data_dir = mkOption { + type = types.path; + default = "${cfg.dataDir}/store"; + defaultText = "\${cfg.dataDir}/store"; + description = "Directory for tranquil-store files"; + }; + }; + }; + }; + + description = '' + Configuration options to set for the service. Secrets should be + specified using {option}`environmentFile`. + + Refer to + for available configuration options. + ''; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + (lib.mkIf cfg.database.createLocally { + services.postgresql = { + enable = true; + ensureDatabases = [ cfg.user ]; + ensureUsers = [ + { + name = cfg.user; + ensureDBOwnership = true; + } + ]; + }; + + services.tranquil-pds.settings.database.url = + lib.mkDefault "postgresql:///${cfg.user}?host=/run/postgresql"; + + systemd.services.tranquil-pds = { + requires = [ "postgresql.service" ]; + after = [ "postgresql.service" ]; + }; + }) + + { + users.users.${cfg.user} = { + isSystemUser = true; + inherit (cfg) group; + home = cfg.dataDir; + }; + + users.groups.${cfg.group} = { }; + + systemd.tmpfiles.settings."tranquil-pds" = + lib.genAttrs + [ + cfg.dataDir + cfg.settings.storage.path + cfg.settings.tranquil_store.data_dir + ] + (_: { + d = { + mode = "0750"; + inherit (cfg) user group; + }; + }); + + environment.etc = { + "tranquil-pds/config.toml".source = + let + conf = settingsFormat.generate "tranquil-pds.toml" cfg.settings; + in + pkgs.runCommandLocal "validated-tranquil-config" { nativeBuildInputs = [ cfg.package ]; } '' + tranquil-server --config ${conf} validate --ignore-secrets + ln -s ${conf} $out + ''; + }; + + systemd.services.tranquil-pds = { + description = "Tranquil PDS - ATProtocol Personal Data Server"; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + UMask = "0077"; + ExecStart = lib.getExe cfg.package; + Restart = "on-failure"; + RestartSec = 5; + + WorkingDirectory = cfg.dataDir; + StateDirectory = "tranquil-pds"; + ReadWritePaths = [ + cfg.settings.storage.path + ]; + + EnvironmentFile = cfg.environmentFiles; + + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; + ProtectProc = "invisible"; + ProcSubset = "pid"; + 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" + "AF_UNIX" + ]; + RestrictNamespaces = true; + LockPersonality = true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + PrivateMounts = true; + SystemCallFilter = [ + "@system-service" + "~@privileged @resources" + ]; + SystemCallArchitectures = "native"; + }; + }; + } + ] + ); + + meta.maintainers = with lib.maintainers; [ nelind ]; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index b669f33158ee..2791b39ca543 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1708,6 +1708,7 @@ in tracee = handleTestOn [ "x86_64-linux" ] ./tracee.nix { }; traefik = runTestOn [ "aarch64-linux" "x86_64-linux" ] ./traefik.nix; trafficserver = runTest ./trafficserver.nix; + tranquil-pds = runTest ./tranquil-pds.nix; transfer-sh = runTest ./transfer-sh.nix; transmission_4 = runTest ./transmission.nix; trezord = runTest ./trezord.nix; diff --git a/nixos/tests/tranquil-pds.nix b/nixos/tests/tranquil-pds.nix new file mode 100644 index 000000000000..db24c899b858 --- /dev/null +++ b/nixos/tests/tranquil-pds.nix @@ -0,0 +1,35 @@ +{ lib, ... }: +{ + name = "tranquil-pds"; + + nodes.machine = + { pkgs, ... }: + { + services.tranquil-pds = { + enable = true; + database.createLocally = true; + + settings = { + server = { + hostname = "pds"; + port = 8080; + }; + + secrets = { + allow_insecure = true; + jwt_secret = "test-jwt-secret-must-be-32-chars-long"; + dpop_secret = "test-dpop-secret-must-be-32-chars-long"; + master_key = "test-master-key-must-be-32-chars-long"; + }; + }; + }; + }; + + testScript = '' + machine.wait_for_unit("tranquil-pds.service") + machine.wait_for_open_port(8080) + machine.succeed("curl --fail http://localhost:8080") + ''; + + meta.maintainers = with lib.maintainers; [ nelind ]; +} diff --git a/pkgs/by-name/tr/tranquil-pds-frontend/package.nix b/pkgs/by-name/tr/tranquil-pds-frontend/package.nix new file mode 100644 index 000000000000..ced153fb08dd --- /dev/null +++ b/pkgs/by-name/tr/tranquil-pds-frontend/package.nix @@ -0,0 +1,61 @@ +{ + lib, + stdenvNoCC, + fetchgit, + nodejs, + pnpm, + pnpmConfigHook, + fetchPnpmDeps, +}: + +stdenvNoCC.mkDerivation (finalAttrs: { + pname = "tranquil-frontend"; + version = "0.6.3"; + + src = fetchgit { + url = "https://tangled.org/tranquil.farm/tranquil-pds"; + tag = "v${finalAttrs.version}"; + hash = "sha256-TORNOFPlbCt4QWNd+bmxkShTUvT/5ynOj+UBYITAhg8="; + }; + sourceRoot = "${finalAttrs.src.name}/frontend"; + + pnpmDeps = fetchPnpmDeps { + inherit (finalAttrs) + pname + version + src + sourceRoot + ; + inherit pnpm; + fetcherVersion = 4; + hash = "sha256-qbmIAvE/3u/NB5x9bERCGQqwiDLkzjff3QchgR+ZDFs="; + }; + + strictDeps = true; + __structuredAttrs = true; + + nativeBuildInputs = [ + pnpm + nodejs + pnpmConfigHook + ]; + + buildPhase = '' + runHook preBuild + pnpm build + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + cp -r ./dist $out + runHook postInstall + ''; + + meta = { + description = "First party frontend for the Tranquil PDS implementation"; + homepage = "https://tangled.org/tranquil.farm/tranquil-pds"; + license = lib.licenses.agpl3Plus; + maintainers = with lib.maintainers; [ nelind ]; + }; +}) diff --git a/pkgs/by-name/tr/tranquil-pds/package.nix b/pkgs/by-name/tr/tranquil-pds/package.nix new file mode 100644 index 000000000000..9d274810bc64 --- /dev/null +++ b/pkgs/by-name/tr/tranquil-pds/package.nix @@ -0,0 +1,47 @@ +{ + lib, + fetchgit, + rustPlatform, + pkg-config, + openssl, + protobuf, + nixosTests, +}: + +rustPlatform.buildRustPackage (finalAttrs: { + pname = "tranquil-pds"; + version = "0.6.3"; + + src = fetchgit { + url = "https://tangled.org/tranquil.farm/tranquil-pds"; + tag = "v${finalAttrs.version}"; + hash = "sha256-TORNOFPlbCt4QWNd+bmxkShTUvT/5ynOj+UBYITAhg8="; + }; + + cargoHash = "sha256-tQk9WQZmaG2XEx5gocPhYd8fZ2cikvduhln5h/w+WZA="; + + __structuredAttrs = true; + + nativeBuildInputs = [ + pkg-config + protobuf + ]; + + buildInputs = [ + openssl + ]; + + # the tranquil test suite has shown itself virtually impossible to complete on most hardware thus stopping reviews. + # disable the check phase for now + doCheck = false; + + passthru.tests = { inherit (nixosTests) tranquil-pds; }; + + meta = { + description = "Tranquil ATProto Personal Data Server implementation written in Rust"; + homepage = "https://tangled.org/tranquil.farm/tranquil-pds"; + license = lib.licenses.agpl3Plus; + maintainers = with lib.maintainers; [ nelind ]; + mainProgram = "tranquil-server"; + }; +})