This repository has no description
0

Configure Feed

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

1{ 2 self, 3 config, 4 pkgs, 5 ... 6}: 7let 8 domain = "pds.lassul.us"; 9 cfg = config.services.tranquil-pds; 10 package = self.packages.${pkgs.stdenv.hostPlatform.system}.tranquil-pds; 11 zitadelEnv = config.lass.zitadel.projects.pds.apps.web.envFile.path; 12in 13{ 14 # ATProto PDS (Tranquil). Accounts get handles <name>.pds.lassul.us and 15 # log in via id.lassul.us. Accounts are created only by the SSO signup 16 # (no invite code), nginx rejects all other account-creation routes. 17 clan.core.vars.generators.tranquil-pds = { 18 files."secrets.env" = { }; 19 runtimeInputs = [ pkgs.openssl ]; 20 script = '' 21 for var in JWT_SECRET DPOP_SECRET MASTER_KEY; do 22 echo "$var=$(openssl rand -hex 32)" 23 done > "$out/secrets.env" 24 ''; 25 }; 26 27 # send-only mailbox on this host's mailserver (configs/mailserver.nix) for 28 # email verification and password resets 29 mailserver.loginAccounts."pds@lassul.us" = { 30 hashedPasswordFile = config.clan.core.vars.generators.mailserver-pds.files."password-hash".path; 31 sendOnly = true; 32 }; 33 34 # smarthost.env is an environmentFile of tranquil-pds 35 clan.core.vars.generators.mailserver-pds = { 36 files."smarthost.env" = { }; 37 files."password-hash" = { }; 38 runtimeInputs = with pkgs; [ 39 coreutils 40 mkpasswd 41 pwgen 42 ]; 43 script = '' 44 password=$(pwgen -s 32 1) 45 echo "MAIL_SMARTHOST_PASSWORD=$password" > "$out/smarthost.env" 46 mkpasswd -sm bcrypt <<< "$password" > "$out/password-hash" 47 ''; 48 }; 49 50 services.tranquil-pds = { 51 enable = true; 52 inherit package; 53 database.createLocally = true; 54 environmentFiles = [ 55 config.clan.core.vars.generators.tranquil-pds.files."secrets.env".path 56 config.clan.core.vars.generators.mailserver-pds.files."smarthost.env".path 57 zitadelEnv 58 ]; 59 settings = { 60 server = { 61 hostname = domain; 62 invite_code_required = false; 63 # certs come from nginx, not caddy 64 enable_caddy_on_demand_tls = false; 65 }; 66 frontend.dir = package.frontend; 67 # owner's PLC recovery key (public part) 68 secrets.plc_rotation_key = "did:key:zDnaepKZiYEbndTH9NNqoZUa7mvbhdiF3M9g2MCjtnxhijtUS"; 69 email = { 70 from_address = "pds@lassul.us"; 71 from_name = "lassul.us PDS"; 72 smarthost = { 73 host = "mail.lassul.us"; 74 port = 465; 75 tls = "implicit"; 76 }; 77 }; 78 sso.oidc = { 79 issuer = "https://id.lassul.us"; 80 display_name = "lassul.us ID"; 81 }; 82 }; 83 }; 84 85 systemd.services.tranquil-pds = { 86 wants = [ "zitadel-reconcile.service" ]; 87 after = [ "zitadel-reconcile.service" ]; 88 # not in settings: the config file is validated at build time, without 89 # the secrets from environmentFiles that these require 90 environment = { 91 MAIL_SMARTHOST_USERNAME = "pds@lassul.us"; 92 SSO_OIDC_ENABLED = "true"; 93 }; 94 }; 95 96 # only the users listed here get a project grant and can log in 97 lass.zitadel.projects.pds = { 98 access = "declarative"; 99 users = [ "lass@lassul.us" ]; 100 apps.web = { 101 redirectUris = [ "https://${domain}/oauth/sso/callback" ]; 102 authMethod = "post"; 103 envFile = { 104 clientIdVariable = "SSO_OIDC_CLIENT_ID"; 105 clientSecretVariable = "SSO_OIDC_CLIENT_SECRET"; 106 }; 107 }; 108 }; 109 110 # repos, accounts and keys in postgres, blobs on disk 111 lass.backup.state.tranquil-pds = { 112 folders = [ cfg.dataDir ]; 113 preBackup = '' 114 mkdir -p /var/backup/postgresql 115 ${pkgs.sudo}/bin/sudo -u postgres ${config.services.postgresql.package}/bin/pg_dump \ 116 tranquil-pds | ${pkgs.gzip}/bin/gzip > /var/backup/postgresql/tranquil-pds.sql.gz 117 ''; 118 }; 119 120 # handles are served /.well-known/atproto-did on <handle>.pds.lassul.us; 121 # DNS-01 against our own knot, see _acme-challenge.pds.lassul.us in 122 # configs/dns/knot.nix 123 security.acme.certs.${domain} = { 124 extraDomainNames = [ "*.${domain}" ]; 125 dnsProvider = "rfc2136"; 126 environmentFile = config.clan.core.vars.generators.knot-acme-review.files."lego.env".path; 127 group = config.services.nginx.group; 128 }; 129 130 services.nginx.virtualHosts.${domain} = { 131 serverAliases = [ "*.${domain}" ]; 132 useACMEHost = domain; 133 forceSSL = true; 134 locations."/" = { 135 proxyPass = "http://${cfg.settings.server.host}:${toString cfg.settings.server.port}"; 136 recommendedProxySettings = true; 137 # com.atproto.sync.subscribeRepos 138 proxyWebsockets = true; 139 extraConfig = '' 140 proxy_read_timeout 1d; 141 client_max_body_size 10G; 142 ''; 143 }; 144 # password, passkey, delegated and migrated (service-auth) accounts 145 locations."= /xrpc/com.atproto.server.createAccount".return = "403"; 146 locations."= /xrpc/_account.createPasskeyAccount".return = "403"; 147 locations."= /xrpc/_delegation.createDelegatedAccount".return = "403"; 148 }; 149}