···11+#ENC[AES256_GCM,data:uT7liv6i+39HBT1tMkHiTIGhUyXw,iv:92Ka7wMhb4KiL3dntrJ/noU4507aL7JW92CXt3JeSK0=,tag:KY8bJwDhCKvnQ3DUmk/oqA==,type:comment]
22+#ENC[AES256_GCM,data:7OolqxEvGMgPdGPmENWsusNkCH/afKfL/wr20SqC5bzizOTY+vKqJ/JBsc4=,iv:eqo9z16twhExXhbCs2u0XTMK/rJWnXtx8BDx2yPpav8=,tag:uoEXFJo6XP9PRZUYkqMFhQ==,type:comment]
33+JWT_SECRET=ENC[AES256_GCM,data:Mj1HC9XzBr5hjGHdLv+b2FExI+W6tTP5Z9qDomycr2M3OICj4wArt5Gf+YoGDWAgw96y1FueJuA7UZbpzdtdNA==,iv:Eah2ZgY//C0uUXq3rSHYqIWENKJkcdT8NUSIXH2HKVk=,tag:lxWGpzl13VeDg1wo/6cpDQ==,type:str]
44+DPOP_SECRET=ENC[AES256_GCM,data:J2e1d0hyHRyKMSb/pZgb2aLCdWNwtZPAyV5I4f4yvx9zmaxs9KjicP0XODh9VkridbSUM4TRsC8IkuChMSTMhQ==,iv:ibMjSLvE6bxov7jtW99POXgK2Z7EAh5O+E9yUOtzGos=,tag:AnpEB0DM8eAsYx5IETQ74w==,type:str]
55+MASTER_KEY=ENC[AES256_GCM,data:6O0m9MvoE1iWwd9WYpDMkxvIiHF7D3yJcduvKbA9bQwNyNS7ASlX8WtRsW9eYyqzJ9nExUTgsiRKWwrfLiRc8A==,iv:7AOGJcGRPjyD7ryAvZ1AN4u2348TQVBDKNzes3o1d4Q=,tag:ofpWXIfLDgMKUkqsWSSSiQ==,type:str]
66+#ENC[AES256_GCM,data:0/SDGkkw2sqDOIkVdkSD6AhmPdobILxRhYGKj+8Ge45FWN2L0fnhT3s50Q==,iv:qRXdlOH3lEIBZDJhSaLR6fd4OQ5mr/lN6JTgrP3/Gnc=,tag:4srFAugJZ0sg/XrIPB3gpA==,type:comment]
77+PLC_ROTATION_KEY=ENC[AES256_GCM,data:4A7+X1kvYXCjifiDtuoT8nthimenJ/5i0YKYgnvrplzH9b6gaF2yi2KOd2P/qGJzeWNYCV2wAigKsQ3+cs19sQ==,iv:iU+kjxRe+Sm4xhmzj0lFavnR4mgl5WS5yk6vQC6KuSk=,tag:AKcPp+w+NsL1MRb1+gulFw==,type:str]
88+#ENC[AES256_GCM,data:Va4T6FcmXG6JzqOqTGeH2xP1UWI8fsuF0N0OSzKPbgs0oyrWLw==,iv:QykbfWjqo9MSPx+Z7DJPl979RrlU2m3tNgQMJgUKUL0=,tag:9TuIDROLYnHpomzXGRglaw==,type:comment]
99+CLOUDFLARE_API_TOKEN=ENC[AES256_GCM,data:Wp+fQSFdA7mngPTxewSVGBftUEpaLW/TNrHTjVn+rY9rGyqfMIRevw==,iv:b4I8gS8yIURT7/QjJg282eEcXIXkLfV2To7zJlZaFDA=,tag:oZSAESmaHuw59XshEgTMNA==,type:str]
1010+#ENC[AES256_GCM,data:Rwsf2UXpqZZjTOIx7PQrY5VKYLvosACnAcs=,iv:1wwuqeU7slNLoY23WVMUjZ7Ds4rjs49CqSvjKRQ8Yr4=,tag:281fAfeJOMZBb6+5sssDYg==,type:comment]
1111+S3_BUCKET=ENC[AES256_GCM,data:zEBsVVwHOaxu,iv:FFNvGqOnTkSb/hThGE+4jhFVrtQu8UmuuFj1KLHUl4w=,tag:umarOwJihqvRnNXtzfBF9Q==,type:str]
1212+S3_ENDPOINT=ENC[AES256_GCM,data:0atTeoPoeFRbERHVGekwaAFeswWWhbIfqNH07e+WtboFrOM=,iv:MQ19TAXyyFiTy72vV7BNiIEV3mYub6rlnEMfaE5LYFI=,tag:JrpC0Tqf2lBffeS0UwnqyQ==,type:str]
1313+AWS_ACCESS_KEY_ID=ENC[AES256_GCM,data:o5qAatqaETTLuIeYX6wdjCT+8RE=,iv:VtZimAT/dv0naJClbs6Mww9l6xbeQ6J7o5zP9axdVb8=,tag:fsPq1GpVVfX9y3yKxo4ZXw==,type:str]
1414+AWS_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:xmOHAOBYKgEvTwi3IojhjXAxmCDjKD54ZqeLdypdPBCz6WgoCvXFKA==,iv:j8CknNrur0D0imZdMBI+1CLAD29raDSmowz2+5N4bU8=,tag:tIttmCQsXH8Zq+w6oNdMjw==,type:str]
1515+AWS_REGION=ENC[AES256_GCM,data:WtfRdA==,iv:z5V8PZAlArDKnxPepFd3DGOu1uHW8o8nvbuFBbESi1I=,tag:os0joOzJO9EpaTpeIRcLdQ==,type:str]
1616+#ENC[AES256_GCM,data:R84B2kDI3ksykBe5,iv:7IZFFAnaBqrnrMM24pDgBSGHqnLb2mPjgg46/LSRV+w=,tag:UigfhDaWXLLH/6KQkJekyg==,type:comment]
1717+SSO_DISCORD_CLIENT_ID=ENC[AES256_GCM,data:Uv+XhViVoEbpI2fWQ9RjU9CjCQ==,iv:MvxNPKKRPe64APkkQBl7bEH1NqLD14mAxLk1EbgV0hE=,tag:gmvLUgJb+APs6qr73LJKpg==,type:str]
1818+SSO_DISCORD_CLIENT_SECRET=ENC[AES256_GCM,data:c4hoEm3ITaT8WWjez+qFo/nrsIs5PtCBnolGDt15AcQ=,iv:qTUxN79YxAKBJUkx5wyrX/4u3u1BEdEJBiUQ6YypLgk=,tag:j3dJ9tTW+RuN9FuOhqzHpQ==,type:str]
1919+#ENC[AES256_GCM,data:GFLA9tgtlgwWaqPG+Hhk6b5DD8DlnSM/iZkZcPQKQFKuqxuVE/oAd+n085zi18FKaqr+q1t6Xq/+HV09uEI=,iv:dlD06U+hXgmkXTztm1ZjcG10Ip4IPPFxxAb1C82saWE=,tag:/aG7Mw9N120fhxYHx0pvaQ==,type:comment]
2020+MAIL_FROM_ADDRESS=ENC[AES256_GCM,data:NBu6w+LxPvPZ7qRBoxZHMvUbPOg+,iv:KBpxZgwwjDSdXjX7mcCNNiL/A90+V0pd84d3OZbfJiA=,tag:3rzQ0dlsT4Fw09+YzFmEGQ==,type:str]
2121+sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLam52UzJyMFBUaWVWWStZ\nNUpBbHFjNHdqc1ZFTE96Q0laWWJjRDFHRm53ClIzVjd0UnRDS09jTmdGZ0MyZm5s\nd3I5UG5SUFB0VWFFUHgraFNhZFNzclEKLS0tIHlGNE1uTFBBUEZrM0RSU0dPMWZu\ncWtuSEVhRUtBMkpiSk9GWWhoTnZxZEkKiKWdUZ4mqvqAmqd013xd5tW5UGcMY8Wi\nkc/y1UlZnJFMU3OoICdWXEbet81TQriNxPjXjhgmBUlK3zfzy6LGIg==\n-----END AGE ENCRYPTED FILE-----\n
2222+sops_age__list_0__map_recipient=age1h08rnd0jeddf55l6l3rf6dlwwh7mngcxy92tyz0hfysjqx4wvgrq6vmah2
2323+sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLS2ZYSExScEhhV1NRZUc4\nU1pDOU5ydVlPb2NNdHUxTmNYMHhqMDBRU3o0Ck91MHRKY2RJWG1FRlhGbGRNSHRw\nVGRpV3o0K3ZzaWxJK1NqNG5oRnYwY0EKLS0tIFFOWm05ZEtSMUFsME1WMGtKdEFs\nU1RCR29vREwzQXJZSXJoVmR3Y2IvTUEKps6/I4f4Ec73c+N0JN+xSyQfMfEsqHda\noC++w3UpkCkyNKiLWbbTaWMCjRoSX7jhKEmCZvoU7J1X4pTRFHFAQQ==\n-----END AGE ENCRYPTED FILE-----\n
2424+sops_age__list_1__map_recipient=age1dhxleu7puseq4fz5gprzdssprdd452kjry2n47xaqfh22p5eyqfs68zysl
2525+sops_lastmodified=2026-03-27T03:46:07Z
2626+sops_mac=ENC[AES256_GCM,data:4IaypLApjBuyujeJNsBjYN3i3TW7Duvj532ex5EdtkrCuNhmoB+YoC6yoO3ap6Sq21M8yBmeyZKfxrDHQAUL+xoxQXQAyj/Ot1ZbGLwo/w1EI5ka/0+ohOxkb/Bc75ioGyu8x+605dEQYst2Sm6nTKkEclDoaM3FzZGd6gHtM8g=,iv:4sKe7PxjGw/curGjnq3d4bRb7N3EcXFd0e44oZYY3ZA=,tag:Q6JtBs31lu/KEc4WoXEXiQ==,type:str]
2727+sops_unencrypted_suffix=_unencrypted
2828+sops_version=3.11.0
+2-1
servers/kuribo/configuration.nix
···55 ../../modules/gc.nix
66 ../../users/users.nix
77 ./caddy.nix
88- ./pds.nix
88+ ./pds.nix # Old PDS on port 3000 - remove after migration
99+ ./tranquil-pds.nix # Tranquil on port 3001 at new.pds.starhaven.dev
910 ./tangled.nix
1011 ./papermario-dx-build.nix
1112 ];
+73
servers/kuribo/tranquil-pds.nix
···11+# STAGING CONFIG: Tranquil at new.pds.starhaven.dev (port 3001)
22+# Old PDS stays at pds.starhaven.dev (port 3000)
33+# After migration, change hostname back to pds.starhaven.dev and port to 3000
44+{ config, pkgs, ... }:
55+{
66+ sops.secrets.tranquil-pds = {
77+ sopsFile = ../../secrets/kuribo/tranquil-pds.env;
88+ format = "dotenv";
99+ owner = "tranquil-pds";
1010+ group = "tranquil-pds";
1111+ };
1212+1313+ services.tranquil-pds = {
1414+ enable = true;
1515+ database.createLocally = true;
1616+ environmentFiles = [ config.sops.secrets.tranquil-pds.path ];
1717+1818+ settings = {
1919+ server = {
2020+ # STAGING: temporary subdomain during migration
2121+ hostname = "new.pds.starhaven.dev";
2222+ port = 3001;
2323+ user_handle_domains = [ ".starhaven.dev" ];
2424+ contact_email = "admin@starhaven.dev";
2525+2626+ # Open registration (no invite required)
2727+ invite_code_required = false;
2828+ };
2929+3030+ storage = {
3131+ # S3 config comes from environment file
3232+ backend = "s3";
3333+ };
3434+3535+ email = {
3636+ from_address = "noreply@starhaven.dev";
3737+ from_name = "Star Haven";
3838+ };
3939+4040+ # Discord SSO (credentials in env file)
4141+ sso.discord = {
4242+ enabled = true;
4343+ display_name = "Discord";
4444+ };
4545+4646+ # Accept repo imports for migration
4747+ import = {
4848+ accepting = true;
4949+ max_size = 1073741824; # 1GB
5050+ };
5151+ };
5252+ };
5353+5454+ # Caddy: serve both old PDS and new Tranquil
5555+ services.caddy.virtualHosts."new.pds.starhaven.dev" = {
5656+ extraConfig = ''
5757+ tls {
5858+ dns cloudflare {env.CLOUDFLARE_API_TOKEN}
5959+ }
6060+ reverse_proxy http://127.0.0.1:3001
6161+ '';
6262+ };
6363+6464+ # Caddy needs the secrets for CLOUDFLARE_API_TOKEN
6565+ systemd.services.caddy = {
6666+ after = [
6767+ "tranquil-pds.service"
6868+ "ondemand-tls-helper.service"
6969+ "sops-nix.service"
7070+ ];
7171+ serviceConfig.EnvironmentFile = config.sops.secrets.tranquil-pds.path;
7272+ };
7373+}