{"collection":"posts","slug":"1732585567703-pure-internet-bluesky","cid":"bafkreiey22nlo3yw74csliw5pgi5kj7v4cw4oo6arz5mafpqisqydglvwy","title":"Pure Internet: Bluesky","excerpt":"Static-site hosting on Bluesky's AT Protocol using content-addressed blob storage.","body":"After [NFC cards with data URLs and ENS+IPFS](https://pureinternet.eth.limo/#UHVyZSBJbnRlcm5ldC4gQWxsIHRoZSBjb250ZW50IHlvdSBzZWUgaXMgZW5jb2RlZCBhcyBiYXNlNjQgYW5kIHN0b3JlZCBvbiBhbiBORkMgY2FyZC4gVGhlcmUncyBubyB0cmFkaXRpb25hbCBzZXJ2ZXIsIGp1c3QgYSBzaW5nbGUgcGllY2Ugb2YgSFRNTCBwaW5uZWQgdG8gSVBGUy4gUHVyZSBJbnRlcm5ldC4=), I [got a static site running on Bluesky's AT Protocol](https://amanita.us-east.host.bsky.network/xrpc/com.atproto.sync.getBlob?did=did:plc:p5xem22ammiafn5kxonaksfa\u0026cid=bafkreih2pbifus4ed6p7kfuqjbjbqmzewlnyaz7f7ykmk5bvchkj7w3eb4). This experiment was inspired by [Daniel Mangum's exploration of atproto's storage capabilities](https://danielmangum.com/posts/this-website-is-hosted-on-bluesky/).\n\nBluesky is mostly known as a social platform. The AT Protocol underneath is a content-addressable system with built-in distribution. Every blob gets a CID, retrievable through any AT Proto node. It's IPFS in different clothes.\n\nIf you can upload arbitrary blobs and get stable URLs back, you can use it as web hosting. Here's the recipe.\n\n1. First, create a session with your Bluesky credentials:\n\n```\ncurl -X POST 'https://bsky.social/xrpc/com.atproto.server.createSession' \\ -H 'Content-Type: application/json' \\ -d '{\"identifier\": \"your-handle.bsky.social\", \"password\": \"your-password\"}'\n```\n\nSave the `accessJwt` from the response for the next steps.\n\n2. Create an HTML file (`index.html`) with your website content.\n3. Upload your HTML file as a blob:\n\n```\ncurl -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'\n```\n\nThe response will include a blob reference with a CID. Save this CID for the next step.\n\n4. Create a record referencing your blob:\n\n```\ncurl -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 } } }'\n```\n\n5. Get the URL of your website:\n\n```\ncurl -I 'https://bsky.social/xrpc/com.atproto.sync.getBlob?did=YOUR_DID\u0026cid=YOUR_BLOB_CID'\n```\n\nThe 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\u0026cid=bafkreih2pbifus4ed6p7kfuqjbjbqmzewlnyaz7f7ykmk5bvchkj7w3eb4):\n\n```\nhttps://amanita.us-east.host.bsky.network/xrpc/com.atproto.sync.getBlob?did=did:plc:p5xem22ammiafn5kxonaksfa\u0026cid=bafkreih2pbifus4ed6p7kfuqjbjbqmzewlnyaz7f7ykmk5bvchkj7w3eb4\n```\n\nThe URL parts: `amanita.us-east.host.bsky.network` is a Bluesky content delivery node, `com.atproto.sync.getBlob` is the retrieval endpoint, `did` is the content owner, `cid` is the content hash.\n\nThe trade-offs are real. You depend on Bluesky's infrastructure. Blobs have size caps. The platform isn't built for static hosting, so content could disappear. The setup is just dead simple.\n\nIt's not pure internet in the sovereign sense, since the federation still owns the delivery. But it leaves a question hanging: how far can a social protocol stretch before it becomes a general-purpose CDN?","tags":["web-development","alternative-hosting","at-protocol","bluesky","decentralization","ipfs","web-hosting"],"published":true,"createdAt":"2024-11-25T17:46:00Z","updatedAt":"2026-07-16T14:56:30Z"}
