## running different pieces of atproto for how the pieces fit together: [atproto for distsys engineers](https://atproto.com/articles/atproto-for-distsys-engineers). it frames the firehose as an event log and appviews as precomputed views over it nothing below needs a specific vendor. i often use [fly](https://fly.io) for small services out of habit — [render](https://render.com), [railway](https://railway.app), or a plain vps on [hetzner](https://www.hetzner.com/cloud), [digitalocean](https://www.digitalocean.com), or [ovh](https://www.ovhcloud.com) all work, and a vps is usually cheaper if you know what you're doing
glossary **client-side apps.** the app is a static bundle. the user signs in with atproto oauth and reads and writes their own PDS. there is no backend to run. [doodl](https://doodl.waow.tech) stores drawings as PDS blobs. these do not appear in my infra costs. i might use a [cloudflare worker](https://developers.cloudflare.com/workers/) for link previews tho. [wisp.place](https://wisp.place) hosts the bundle on atproto itself, which is how [at-me](https://at-me.wisp.place) and [punch](https://sites.wisp.place/zzstoatzz.io/punch/) are served. **microcosm.** already indexes the whole network, so a lot of what you'd build a backend for is a http call away. free, no auth, CORS, so the browser can call it directly: ```bash # how many likes does this post have? curl "https://constellation.microcosm.blue/xrpc/blue.microcosm.links.getBacklinksCount\ ?subject=at://did:plc:xbtmt2zjwlrfegqvch7fboei/app.bsky.feed.post/3mn4baqvpoc26\ &source=app.bsky.feed.like:subject.uri" # {"total":96} # who is this, and where is their PDS? curl "https://slingshot.microcosm.blue/xrpc/com.bad-example.identity.resolveMiniDoc\ ?identifier=zzstoatzz.io" # {"did":"did:plc:xbtmt2zjwlrfegqvch7fboei","handle":"zzstoatzz.io", # "pds":"https://pds.zzstoatzz.io","signing_key":"zQ3shpq..."} ``` `source` is just `{collection}:{path}`, so that works for any lexicon, not only bluesky. [constellation](https://constellation.microcosm.blue) does backlinks (likes, follows, replies, quotes), [slingshot](https://slingshot.microcosm.blue) does identity and records, [spacedust](https://spacedust.microcosm.blue) streams live interactions, and [ufos](https://ufos-api.microcosm.blue) shows what lexicons exist. i wrote [protopack](https://tangled.org/zzstoatzz.io/protopack) to make agents fluent in them. **appviews.** an appview consumes the firehose, indexes records, and serves them over xrpc. [happyview](https://happyview.dev) writes that plumbing for you, so you define lexicons instead of maintaining a firehose consumer. for storage, start with sqlite on the machine — one file, fast, usually enough. sqlite is not highly available, so if you need more than one instance or you can't lose the disk, use postgres, managed if you'd rather not run it (eg [neon](https://neon.com), which [plyr.fm](https://plyr.fm) uses). [turso](https://turso.tech) is hosted sqlite with replicas if you want to stay in that world. appview cost scales with the size of the corpus, not with traffic. that surprised me. **PDS.** stock image and a persistent volume. my whole deploy config is [three files](https://tangled.org/zzstoatzz.io/pds-infra). blobs live on the volume, so disk is what grows. **relays.** a relay subscribes to every PDS in the network, so the traffic allowance decides the machine. check it before you pick a region — hetzner's EU datacenters include 20 TB/mo where their US ones include 3–5 TB.
### summary of what, how, where and $ figures are what i pay, from a daily snapshot i publish to my PDS as [`io.zzstoatzz.cost.snapshot`](https://pds.ls/at://did:plc:xbtmt2zjwlrfegqvch7fboei/io.zzstoatzz.cost.snapshot). | thing | what i run | where | $/mo | |---|---|---|---| | client-side app | [doodl](https://doodl.waow.tech), [at-me](https://at-me.wisp.place), [punch](https://sites.wisp.place/zzstoatzz.io/punch/) | any static host — [wisp.place](https://wisp.place) or [cloudflare](https://developers.cloudflare.com/workers/) | ~0 | | appview (framework) | [status.zzstoatzz.io](https://status.zzstoatzz.io) | [happyview](https://happyview.dev) on one small vm | ~6 | | appview (custom) | [typeahead](https://tangled.org/zzstoatzz.io/typeahead), [pub-search](https://tangled.org/zzstoatzz.io/pub-search), [coral](https://tangled.org/zzstoatzz.io/coral) | small vm + sqlite, or managed postgres ([neon](https://neon.com)) if you need HA | 5–25 each | | PDS | [pds.zzstoatzz.io](https://pds.zzstoatzz.io) — stock [bluesky-social/pds](https://github.com/bluesky-social/pds) image | any vm with a persistent volume ([my config](https://tangled.org/zzstoatzz.io/pds-infra)) or [cirrus](https://github.com/ascorbic/cirrus) | 10.64 | | relay | [relay.waow.tech](https://relay.waow.tech) ([go/indigo](https://github.com/bluesky-social/indigo/tree/main/cmd/relay)) and [zlay.waow.tech](https://zlay.waow.tech) ([zig](https://tangled.org/zat.dev/zlay)) | [hetzner](https://www.hetzner.com/cloud) cx53 and cx43 in `fsn1`, k3s, [terraform](https://tangled.org/zzstoatzz.io/relay) | 34.99 and 18.49 | before you deploy an appview, check whether [microcosm](https://microcosm.blue) already answers your question — you deploy nothing and it costs nothing. also i will say that free tier cloudflare is quite generous, pages/workers can take you [a long way](https://bsky.app/profile/zzstoatzz.io/post/3mqsmy6duv225) and go sponsor fig! https://github.com/sponsors/uniphil