Notes on hosting an ATProto PDS on Cloudflare
tldr;
It is possible: https://atprotify.me
The pay-as-you-go cloud model (aka serverless) is not the most natural fit for hosting a PDS. PDSs communicate with the relay through a WebSocket (a long-lived, stateful connection), while the serverless computing model is usually based on short-lived, stateless functions that spin up and down on demand.
I've always been a fan of Cloudflare products, and when I read about Durable Objects and their support for WebSockets, I was curious to see how hard it would be to host a PDS on its platform. I was inspired by Eli Mallon's post on the very minimal requirements for interacting with the ATProto network: https://blog.stream.place/3lut7mgni5s2k (thanks for listing the endpoints to implement!)
Bluesky's PDS reference implementation is written in TypeScript, a firstclass language in the Cloudflare ecosystem. Conveniently, Cloudflare offers a database service based on SQLite (called D1), which happens to be the storage backend used by Bluesky's PDS. Lastly, I was pleasantly surprised to discover that Bluesky uses Kysely, my favorite library for interacting with SQL databases.
With all those pieces in place, I was able to hack together a proof-of-concept implementation of a working PDS. (I call it a PDS for simplicity, but it would be more accurate to call it an actor in the network, since it barely implements what's needed to be seen by ATProto relays and appviews.)
Here are some scattered notes about the obstacles I encountered and what I learned.
Using Official libraries
The two main libraries on which the official PDS is built are @atproto/repo and @atproto/pds. The former implements the repo (commit chain, MST..) and is storage-agnostic. The latter implements a SQLite-based storage backend for @atproto/repo and provides a full PDS server (XRPC endpoints, account management, etc).
@atproto/repo can be used out of the box on Cloudflare workers, since it's just a library (which, importantly, doesn't rely on any Node features unavailable in Cloudflare Workers). @atproto/pds, on the other hand, is a normal standalone server, so it can't be hosted on Cloudflare Workers as is. I shamelessly borrowed a lot of the storage-related code from it, tho.
Databases and multitenancy
Bluesky's PDS can host several repositories. The PDS uses one database for account information, another for sequencing communication with the relay and a third one for caching did documents. When it comes to repo storage, the PDS uses one SQLite database per repository.
I wanted my PDS to host several repos as well, but annoyingly, D1 databases can't be created dynamically and must be provisioned beforehand. I ended up modifying the schema I borrowed from @atprotp/pds to support multiple repos on a single DB. It would be very easy to add sharding.
DIDs resolution
It made sense to use did:web for my repo identifiers. Handles in ATProto are domain names that resolve to DIDs (which themselves resolve to DID documents). Handles can be resolved to DIDs either using DNS TXT records or a well-known URLs.
The easiest approach for me was to use the well-known URL strategy because I didn't want to pollute atprotify.me with DNS records. Unfortunately, Cloudflare doesn't provide a way to associate wildcard DNS records (i.e. <star>.atprotify.me) with a Worker, making it impossible to implement the well-known URL directly. I ended up pointing <star>.atprotify.me to a Caddy server elsewhere, acting as a reverse proxy for the Worker and sending the subdomain as an HTTP header. (I wanted this to be a fully Cloudflare-hosted PDS, but it is what it is.)
subscribeRepos
This end point (the PDS firehose) was the most difficult part to implement. Cloudflare offers what they call "hibernation" for websockets, which is what allows it to remain "serverless". https://developers.cloudflare.com/durable-objects/examples/websocket-hibernation-server/ It is very dependant on Cloudflare Durable Objects architecture, which prevented me from reusing much code from @atproto/pds.
Conclusion
Seeing ATProto records appear on blusky from a new form of PDS is exhilarating.
This is only a proof of concept, but it should be possible to implement a production grade PDS on Cloudflare. Whether it makes sense economically is a different question.