Something went wrong. Try again.
Our Personal Data Server from scratch!
Something went wrong. Try again.
tranquil-pds module.nix
7.7 kB · 265 lines
Nix
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266{ lib, pkgs, config, ...}:let cfg = config.services.tranquil-pds;
inherit (lib) types mkOption;
settingsFormat = pkgs.formats.toml { };in{ _class = "nixos";
disabledModules = [ "services/web-apps/tranquil-pds.nix" ];
options.services.tranquil-pds = { enable = lib.mkEnableOption "tranquil-pds AT Protocol personal data server";
package = mkOption { type = types.package; default = pkgs.callPackage ./default.nix { }; defaultText = lib.literalExpression "pkgs.tranquil-pds"; description = "The tranquil-pds package to use"; };
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 = "[::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 = mkOption { type = types.nullOr types.package; default = pkgs.callPackage ./frontend.nix { }; defaultText = lib.literalExpression "pkgs.tranquil-frontend"; description = "Frontend package to be served by the backend"; }; };
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 <https://tangled.org/tranquil.farm/tranquil-pds/blob/main/example.toml> 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} = { };
# TODO: probably should split these out so only the directories that are actually used made and configured 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 - AT Protocol 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"; }; }; } ] );}