Something went wrong. Try again.
gotta store my records
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242name: crate-devnet
# A tranquil (isolated, deterministic) local atproto stack for testing# cross-account crate features that depend on Constellation indexing:# adoption (adopt-or-mint), the edit-inbox. Point crate's# SLINGSHOT_URL/CONSTELLATION_URL at this compose's slingshot/constellation# ports instead of the public services. See README.md.## Nothing here talks to the public plc.directory: the `plc` service below is# a local PLC directory that the PDS registers its DIDs with and that# slingshot and crate resolve them from, so a run never publishes test# accounts to the public network.## Slingshot is required even with one PDS hosting every test account: our# OAuth login resolves handles via Slingshot's bespoke resolveMiniDoc# endpoint, which a raw PDS doesn't implement (a PDS only serves the# standard com.atproto.* surface for its own repos).
services: # The PLC directory server reads its Postgres on boot and migrates it, so # it waits for this one to be healthy. plc-db: image: postgres:16-alpine environment: POSTGRES_USER: plc POSTGRES_PASSWORD: plc POSTGRES_DB: plc volumes: - plc-db-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U plc -d plc"] interval: 2s timeout: 3s retries: 30
# Bluesky's reference did:plc directory. The only published image is # linux/amd64, so Apple silicon hosts run it under emulation. plc: platform: linux/amd64 image: ${PLC_IMAGE:?run make e2e-images-verify or follow e2e/README.md} depends_on: plc-db: condition: service_healthy ports: # Published so crate's server, which runs on the host, can set # PLC_DIRECTORY_URL=http://localhost:2582. - "2582:2582" environment: PORT: "2582" DEBUG_MODE: "1" LOG_ENABLED: "true" DB_CREDS_JSON: '{"username":"plc","password":"plc","host":"plc-db","port":5432,"database":"plc"}' DB_MIGRATE_CREDS_JSON: '{"username":"plc","password":"plc","host":"plc-db","port":5432,"database":"plc"}' healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost:2582/_health"] interval: 2s timeout: 3s retries: 30
pds: image: ghcr.io/bluesky-social/pds:0.4 depends_on: plc: condition: service_healthy ports: - "2584:3000" # Also on its "native" port: PDS_HOSTNAME=localhost + PDS_PORT=3000 # get baked into each account's DID doc service endpoint # (http://localhost:3000) at creation time, and crate's server # runs on the host (not in this compose network) — it needs # localhost:3000 to actually reach the PDS to complete OAuth. - "3000:3000" volumes: - pds-data:/pds environment: PDS_HOSTNAME: localhost PDS_PORT: "3000" # Lets the plain-http local resource URL past the https-only check, and # relaxes SSRF protection so the PDS can call other containers by # service name (jetstream, constellation) instead of a public host. PDS_DEV_MODE: "true" PDS_DATA_DIRECTORY: /pds PDS_BLOBSTORE_DISK_LOCATION: /pds/blocks PDS_BLOB_UPLOAD_LIMIT: "104857600" PDS_DID_PLC_URL: http://plc:2582 PDS_BSKY_APP_VIEW_URL: https://api.bsky.app PDS_BSKY_APP_VIEW_DID: did:web:api.bsky.app PDS_REPORT_SERVICE_URL: https://mod.bsky.app PDS_REPORT_SERVICE_DID: did:plc:ar7c4by46qjdydhdevvrndac # No crawlers: jetstream below pulls straight from this PDS, so there's # no relay to notify. PDS_CRAWLERS: "" PDS_INVITE_REQUIRED: "false" PDS_RATE_LIMITS_ENABLED: "false" LOG_ENABLED: "true" PDS_JWT_SECRET: ${PDS_JWT_SECRET} PDS_ADMIN_PASSWORD: ${PDS_ADMIN_PASSWORD} PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX: ${PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX} healthcheck: # com.atproto.server.describeServer is a required, unauthenticated # endpoint on every PDS — a safer bet than guessing at a health path. test: ["CMD", "node", "-e", "fetch('http://localhost:3000/xrpc/com.atproto.server.describeServer').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"] interval: 5s timeout: 5s retries: 20
# jetstream's image runs as a non-root distroless user; named volumes are # created root-owned, so this one-shot container fixes ownership before # jetstream tries to mkdir into it. jetstream-data-init: image: busybox command: ["chown", "-R", "65532:65532", "/data"] volumes: - jetstream-data:/data
jetstream: image: ${JETSTREAM_IMAGE:?run make e2e-images-verify or follow e2e/README.md} depends_on: pds: condition: service_healthy plc: condition: service_healthy jetstream-data-init: condition: service_completed_successfully ports: - "8090:8080" volumes: - jetstream-data:/data environment: # A single PDS serves listRepos/subscribeRepos/getRepo for its own # hosted accounts identically to how a relay would — no separate relay # needed for a one-PDS devnet. JETSTREAM_RELAY_URL: http://pds:3000 # Jetstream verifies commit signatures against the account's DID # document; unset, it asks plc.directory, which 404s on devnet DIDs and # silently drops every event. JETSTREAM_PLC_URL: http://plc:2582 JETSTREAM_DATA_DIR: /data JETSTREAM_LOG_LEVEL: info
constellation: image: ${CONSTELLATION_IMAGE:?run make e2e-images-verify or follow e2e/README.md} depends_on: - jetstream ports: - "6789:6789" command: - "--jetstream=ws://jetstream:8080/subscribe" - "--backend=memory" - "--bind=0.0.0.0:6789"
# PDS_HOSTNAME=localhost already makes the PDS default its # serviceHandleDomains to [".test"], so it self-verifies any <name>.test # handle it hosts — but it only serves plain HTTP internally, and atproto's # bidirectional handle check fetches https://<handle>/.well-known/atproto-did. # Caddy terminates real (locally-CA-signed) TLS for the test handles and # proxies to the PDS over plain HTTP, closing that gap without touching # real DNS or a real cert. caddy: image: caddy:2 volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy-data:/data networks: default: aliases: - alice.test - bob.test - carol.test - dave.test - erin.test - faye.test - gideon.test - hana.test - ivan.test - june.test - kai.test - lina.test - malik.test - nora.test - otis.test - priya.test - quinn.test - rosa.test - sam.test - theo.test
# Caddy's `tls internal` CA is generated into its own data volume; export # the root cert so slingshot (below) can be told to trust it. caddy-ca-export: image: caddy:2 depends_on: - caddy volumes: - caddy-data:/data:ro - caddy-ca:/export entrypoint: ["sh", "-c"] command: - | for i in $(seq 1 30); do f=/data/caddy/pki/authorities/local/root.crt [ -f "$$f" ] && cp "$$f" /export/local-ca.crt && exit 0 sleep 1 done echo "caddy never generated its local CA" >&2 exit 1
slingshot: image: ${SLINGSHOT_IMAGE:?run make e2e-images-verify or follow e2e/README.md} depends_on: caddy-ca-export: condition: service_completed_successfully jetstream: condition: service_started plc: condition: service_healthy ports: - "6790:8080" environment: # did:plc documents come from the local directory, never plc.directory. SLINGSHOT_PLC_DIRECTORY: http://plc:2582 volumes: - slingshot-cache:/cache - caddy-ca:/ca:ro # slingshot's image is debian-slim (has update-ca-certificates, unlike # jetstream/constellation's distroless base) — trust Caddy's local CA # before starting the actual binary. entrypoint: ["sh", "-c"] command: - | cp /ca/local-ca.crt /usr/local/share/ca-certificates/devnet-local-ca.crt update-ca-certificates exec slingshot --jetstream=ws://jetstream:8080/subscribe --cache-dir=/cache --bind=0.0.0.0:8080
volumes: plc-db-data: pds-data: jetstream-data: slingshot-cache: caddy-data: caddy-ca: