Our Personal Data Server from scratch! tranquil.farm
pds rust database fun oauth atproto
221
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 244 lines 6.8 kB view raw
1{ 2 lib, 3 pkgs, 4 config, 5 ... 6}: 7let 8 cfg = config.services.tranquil-pds; 9 10 inherit (lib) types mkOption; 11 12 settingsFormat = pkgs.formats.toml { }; 13in 14{ 15 _class = "nixos"; 16 17 options.services.tranquil-pds = { 18 enable = lib.mkEnableOption "tranquil-pds AT Protocol personal data server"; 19 20 package = mkOption { 21 type = types.package; 22 default = pkgs.callPackage ./default.nix { }; 23 defaultText = lib.literalExpression "pkgs.tranquil-pds"; 24 description = "The tranquil-pds package to use"; 25 }; 26 27 user = mkOption { 28 type = types.str; 29 default = "tranquil-pds"; 30 description = "User under which tranquil-pds runs"; 31 }; 32 33 group = mkOption { 34 type = types.str; 35 default = "tranquil-pds"; 36 description = "Group under which tranquil-pds runs"; 37 }; 38 39 dataDir = mkOption { 40 type = types.str; 41 default = "/var/lib/tranquil-pds"; 42 description = "Working directory for tranquil-pds. Also expected to be used for data (blobs)"; 43 }; 44 45 environmentFiles = mkOption { 46 type = types.listOf types.path; 47 default = [ ]; 48 description = '' 49 File to load environment variables from. Loaded variables override 50 values set in {option}`environment`. 51 52 Use it to set values of `JWT_SECRET`, `DPOP_SECRET` and `MASTER_KEY`. 53 54 Generate these with: 55 ``` 56 openssl rand -base64 48 57 ``` 58 ''; 59 }; 60 61 database.createLocally = mkOption { 62 type = types.bool; 63 default = false; 64 description = '' 65 Create the postgres database and user on the local host. 66 ''; 67 }; 68 69 settings = mkOption { 70 type = types.submodule { 71 freeformType = settingsFormat.type; 72 73 options = { 74 server = { 75 host = mkOption { 76 type = types.str; 77 default = "127.0.0.1"; 78 description = "Host for tranquil-pds to listen on"; 79 }; 80 81 port = mkOption { 82 type = types.int; 83 default = 3000; 84 description = "Port for tranquil-pds to listen on"; 85 }; 86 87 hostname = mkOption { 88 type = types.str; 89 default = ""; 90 example = "pds.example.com"; 91 description = "The public-facing hostname of the PDS"; 92 }; 93 94 max_blob_size = mkOption { 95 type = types.int; 96 default = 10737418240; # 10 GiB 97 description = "Maximum allowed blob size in bytes."; 98 }; 99 }; 100 101 frontend = { 102 enabled = 103 lib.mkEnableOption "serving the frontend from the backend. Disable to serve the frontend manually" 104 // { 105 default = true; 106 }; 107 108 dir = mkOption { 109 type = types.nullOr types.package; 110 default = pkgs.callPackage ./frontend.nix { }; 111 defaultText = lib.literalExpression "pkgs.tranquil-frontend"; 112 description = "Frontend package to be served by the backend"; 113 }; 114 }; 115 116 storage = { 117 path = mkOption { 118 type = types.path; 119 default = "/var/lib/tranquil-pds/blobs"; 120 description = "Directory for storing blobs"; 121 }; 122 }; 123 }; 124 }; 125 126 description = '' 127 Configuration options to set for the service. Secrets should be 128 specified using {option}`environmentFile`. 129 130 Refer to <https://tangled.org/tranquil.farm/tranquil-pds/blob/main/example.toml> 131 for available configuration options. 132 ''; 133 }; 134 }; 135 136 config = lib.mkIf cfg.enable ( 137 lib.mkMerge [ 138 (lib.mkIf cfg.database.createLocally { 139 services.postgresql = { 140 enable = true; 141 ensureDatabases = [ cfg.user ]; 142 ensureUsers = [ 143 { 144 name = cfg.user; 145 ensureDBOwnership = true; 146 } 147 ]; 148 }; 149 150 services.tranquil-pds.settings.database.url = 151 lib.mkDefault "postgresql:///${cfg.user}?host=/run/postgresql"; 152 153 systemd.services.tranquil-pds = { 154 requires = [ "postgresql.service" ]; 155 after = [ "postgresql.service" ]; 156 }; 157 }) 158 159 { 160 users.users.${cfg.user} = { 161 isSystemUser = true; 162 inherit (cfg) group; 163 home = cfg.dataDir; 164 }; 165 166 users.groups.${cfg.group} = { }; 167 168 systemd.tmpfiles.settings."tranquil-pds" = 169 lib.genAttrs 170 [ 171 cfg.dataDir 172 cfg.settings.storage.path 173 ] 174 (_: { 175 d = { 176 mode = "0750"; 177 inherit (cfg) user group; 178 }; 179 }); 180 181 environment.etc = { 182 "tranquil-pds/config.toml".source = settingsFormat.generate "tranquil-pds.toml" cfg.settings; 183 }; 184 185 systemd.services.tranquil-pds = { 186 description = "Tranquil PDS - AT Protocol Personal Data Server"; 187 after = [ "network-online.target" ]; 188 wants = [ "network-online.target" ]; 189 wantedBy = [ "multi-user.target" ]; 190 191 serviceConfig = { 192 User = cfg.user; 193 Group = cfg.group; 194 UMask = "0077"; 195 ExecStart = lib.getExe cfg.package; 196 Restart = "on-failure"; 197 RestartSec = 5; 198 199 WorkingDirectory = cfg.dataDir; 200 StateDirectory = "tranquil-pds"; 201 ReadWritePaths = [ 202 cfg.settings.storage.path 203 ]; 204 205 EnvironmentFile = cfg.environmentFiles; 206 207 CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; 208 ProtectProc = "invisible"; 209 ProcSubset = "pid"; 210 NoNewPrivileges = true; 211 ProtectSystem = "strict"; 212 ProtectHome = true; 213 PrivateTmp = true; 214 PrivateDevices = true; 215 PrivateUsers = true; 216 ProtectHostname = true; 217 ProtectClock = true; 218 ProtectKernelTunables = true; 219 ProtectKernelModules = true; 220 ProtectKernelLogs = true; 221 ProtectControlGroups = true; 222 RestrictAddressFamilies = [ 223 "AF_INET" 224 "AF_INET6" 225 "AF_UNIX" 226 ]; 227 RestrictNamespaces = true; 228 LockPersonality = true; 229 MemoryDenyWriteExecute = true; 230 RestrictRealtime = true; 231 RestrictSUIDSGID = true; 232 RemoveIPC = true; 233 PrivateMounts = true; 234 SystemCallFilter = [ 235 "@system-service" 236 "~@privileged @resources" 237 ]; 238 SystemCallArchitectures = "native"; 239 }; 240 }; 241 } 242 ] 243 ); 244}