Pure Internet: Bluesky

Published 11/25/2024.

#web-hosting#decentralized-web#at-protocol#bluesky#federated

I've been exploring non-standard ways of hosting web content. It's led from NFC cards with data URLs and ENS+IPFS to an unexpected destination: Bluesky's AT Protocol as a hosting platform.

This experiment was inspired by Daniel Mangum's exploration of atproto's storage capabilities.

Most know Bluesky as a decentralized social platform, but the AT Protocol that powers it has intriguing capabilities. It's a content-addressable system with built-in content distribution. Every data piece gets a unique identifier (CID) retrievable through any AT Protocol node. Sound familiar? It should – it's remarkably similar to IPFS.

The idea is simple: if we can upload arbitrary blobs to Bluesky and get stable URLs, why not use it as a minimalist web hosting platform? Here's how to do it:

  1. First, create a session with your Bluesky credentials:
curl -X POST 'https://bsky.social/xrpc/com.atproto.server.createSession' \ -H 'Content-Type: application/json' \ -d '{"identifier": "your-handle.bsky.social", "password": "your-password"}'

Save the accessJwt from the response for the next steps.

  1. Create an HTML file (index.html) with your website content.
  2. Upload your HTML file as a blob:
curl -X POST 'https://bsky.social/xrpc/com.atproto.repo.uploadBlob' \ -H 'Authorization: Bearer YOUR_ACCESS_JWT' \ -H 'Content-Type: text/html' \ --data-binary '@index.html'

The response will include a blob reference with a CID. Save this CID for the next step.

  1. Create a record referencing your blob:
curl -X POST 'https://bsky.social/xrpc/com.atproto.repo.createRecord' \ -H 'Authorization: Bearer YOUR_ACCESS_JWT' \ -H 'Content-Type: application/json' \ -d '{ "repo": "your-handle.bsky.social", "collection": "com.yourdomain.website", "record": { "$type": "com.yourdomain.website", "website": { "$type": "blob", "ref": { "$link": "YOUR_BLOB_CID" }, "mimeType": "text/html", "size": YOUR_FILE_SIZE } } }'
  1. Get the URL of your website:
curl -I 'https://bsky.social/xrpc/com.atproto.sync.getBlob?did=YOUR_DID&cid=YOUR_BLOB_CID'

The response includes a location header with your website's permanent URL. Here's a real example:

https://amanita.us-east.host.bsky.network/xrpc/com.atproto.sync.getBlob?did=did:plc:p5xem22ammiafn5kxonaksfa&cid=bafkreih2pbifus4ed6p7kfuqjbjbqmzewlnyaz7f7ykmk5bvchkj7w3eb4

Breaking down this URL reveals the system’s elegance:

  • amanita.us-east.host.bsky.network is one of Bluesky's content delivery nodes
  • com.atproto.sync.getBlob handles blob retrieval
  • The did parameter identifies the content owner
  • The cid parameter is the content hash

There are trade-offs. You're dependent on Bluesky's infrastructure. There are blob size restrictions. It's not designed for this use case, and there's a potential for content removal. The simplicity is appealing.

This is not "pure" internet in terms of independence, but it is close since we're relying on federated infrastructure. It raises questions about the evolution of social protocols. Could they become general-purpose content distribution networks?