Moving crate to the riotbyte cluster #
The droplet path (deploy/AUTOPUSH.md, crate-pull.timer, deploy/publish.sh)
is replaced by a namespace on the riotbyte DOKS cluster. This is a rebuild, not
a transfer: the droplet is on the "My Team" DigitalOcean account and the cluster
is on the riotbyte one.
Why the hostname does not change #
crate.mokkenstorm.dev stays. The atproto OAuth client_id is
https://crate.mokkenstorm.dev/client-metadata.json, so moving to a riotbyte
domain would invalidate every grant every user has already given and force all
of them to re-authorise. The riotbyte terraform therefore looks the zone up as a
data source rather than adopting it: it routes one hostname without owning a
personal domain that hosts other things.
What terraform creates #
projects/crate/ in the riotbyte infra repo, reusing the shared
modules/project/modules/environment:
- the
crate-productionnamespace - a
crate_productiondatabase and user on the shared DO Postgres, withDATABASE_URLinjected into the app secret - a crate-owned
ghcr-pull-secret, so pulls stop riding on a personal account app-envfrom theCrate - Production1Password item in the Infrastructure vault- a namespace-scoped kubeconfig for CI
- the Cloudflare tunnel ingress route and DNS record, generated from the
module's
project_domainsoutput
k8s/apps/crate-production.yaml in that repo carries the Deployment and
Service. Note the shape differs from the other apps: strategy: Recreate and a
startupProbe with a 20 minute budget, because boot runs a synchronous PDS
backfill before the listener binds.
Prerequisites, all outside this repo #
REGISTRY_USER/REGISTRY_TOKENas tangled repo secrets. Without them the deploy workflow has never published an image, which is why production has been serving a build from 2026-08-03.KUBECONFIG_B64as a tangled repo secret, frommodule.crate.kubeconfig.- A
Crate - Productionitem in the Infrastructure vault with sectionsapp(secret key base, store key),oauth(client jwk) anddiscogs(consumer key, consumer secret).
The Cloudflare trap #
The droplet is reached by a DNS-only A record. The cluster is behind a
Cloudflare Tunnel, and the OAuth path must not sit behind the proxy/WAF without
a skip rule for /client-metadata.json and /jwks.json, with Rocket Loader and
Auto Minify off (they rewrite the Lustre bundle and break it). The riotbyte
terraform manages always_use_https and ssl per zone but none of these, so
they need adding rather than inheriting. Avoiding exactly this is why the alpha
used a DNS-only record; a tunnel is a regression until those rules exist.
Data #
The droplet's Postgres holds the appview index, which is derivable: it is
rebuilt from the PDS and the firehose. A pg_dump and restore is the fast path;
a deliberate rebuild-from-PDS is the honest drill and the one ADR 0002's
disposability argument leans on. Either way, remember the PG15+
GRANT ALL ON SCHEMA public step on the new database.
Nothing else on the droplet is stateful: the image holds compiled code and the secrets arrive from the app secret at runtime.