Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 53 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,66 @@
# @ascorbic/pds
# AT Protocol PDS on Cloudflare Workers

A single-user [AT Protocol](https://atproto.com) Personal Data Server (PDS) that runs on Cloudflare Workers. Host your own Bluesky identity with minimal infrastructure.
A single-user [AT Protocol](https://atproto.com) Personal Data Server (PDS) that runs entirely on Cloudflare's edge infrastructure. Host your Bluesky identity on your own domain with minimal operational overhead.

> **⚠️ Experimental Software**
>
> This is an early-stage project under active development. **You cannot migrate your main Bluesky account to this PDS yet.** Use a test account or create a new identity for experimentation. Data loss, breaking changes, and missing features are expected.
## Why run your own PDS?

## What is this?
A PDS is where Bluesky data lives – posts, follows, profile, and media. Running a personal PDS provides:

A PDS is where your Bluesky data lives – your posts, follows, profile, and media. This package lets you run your own PDS on Cloudflare Workers, giving you control over your data and identity.
- **Independence from platform changes** – If Bluesky's ownership or policies change, the account remains under full control. No billionaire can take it away.
- **Network resilience** – A diverse ecosystem of PDS providers makes the AT Protocol network stronger. More independent servers mean no single point of failure.
- **Data sovereignty** – The repository lives on infrastructure under direct control
- **Portability** – Move between hosting providers without losing followers or identity

## Quick Start
## Architecture

This implementation uses Cloudflare Workers with Durable Objects and R2:

- **Worker** – Stateless edge handler for routing, authentication, and DID document serving
- **Durable Object** – Single-instance SQLite storage for your AT Protocol repository
- **R2** – Object storage for blobs (images, videos)

The result is a PDS that runs at the edge with no servers to manage, automatic scaling, and pay-per-use pricing.

The fastest way to get started:
## Quick Start

```bash
npm create pds
```

This scaffolds a new project, installs dependencies, and runs the setup wizard. See the [PDS package documentation](./packages/pds/) for detailed setup and configuration.

## Packages

- [`@ascorbic/pds`](./packages/pds/) - The main PDS library
- [`create-pds`](./packages/create-pds/) - A CLI tool to scaffold a new PDS project
| Package | Description |
|---------|-------------|
| [`@ascorbic/pds`](./packages/pds/) | The PDS implementation – handles repository operations, federation, OAuth, and the CLI |
| [`@ascorbic/atproto-oauth-provider`](./packages/oauth-provider/) | OAuth 2.1 provider for "Login with Bluesky" |
| [`create-pds`](./packages/create-pds/) | Scaffolding CLI to create new PDS projects |

## Status

This is beta software under active development. Core functionality is complete and tested:

- ✅ Repository operations (create, read, update, delete records)
- ✅ Federation (sync, firehose, blob storage)
- ✅ OAuth 2.1 provider (PKCE, DPoP, PAR)
- ✅ Account migration from existing PDS
- ✅ 140+ tests passing

See the [PDS documentation](./packages/pds/) for current limitations and roadmap.

## Requirements

- Cloudflare account with Workers, Durable Objects, and R2 enabled
- A domain you control (for your handle and DID)
- Node.js 18+ for local development

## Resources

- [AT Protocol Documentation](https://atproto.com)
- [Bluesky](https://bsky.app)
- [Cloudflare Workers](https://developers.cloudflare.com/workers/)

## License

MIT
170 changes: 133 additions & 37 deletions packages/create-pds/templates/pds-worker/README.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,188 @@
# Personal PDS on Cloudflare Workers
# Your Personal PDS

A single-user AT Protocol Personal Data Server running on Cloudflare Workers.

> **⚠️ Experimental Software**
>
> This is an early-stage project under active development. **Do not migrate your main Bluesky account to this PDS yet.** Use a test account or create a new identity for experimentation.

## Setup
## Getting Started

### 1. Install dependencies

```bash
pnpm install
# or: npm install / yarn install
```

### 2. Configure environment
### 2. Configure the PDS

If you haven't already, run the setup wizard:
Run the setup wizard if not already done:

```bash
pnpm pds init
# or
npm run pds init
yarn pds init
```

This prompts for your hostname, handle, and password, then writes configuration to `.dev.vars`.
This prompts for:
- **PDS hostname** – The deployment domain (e.g., `pds.example.com`)
- **Handle** – The Bluesky username (e.g., `alice.example.com`)
- **Password** – For logging in from Bluesky apps

The wizard generates cryptographic keys and writes configuration to `.dev.vars` and `wrangler.jsonc`.

### 3. Run locally

```bash
pnpm dev
```

This starts a local development server at http://localhost:5173.
The PDS is now running at http://localhost:5173. Test it with:

```bash
curl http://localhost:5173/health
curl http://localhost:5173/.well-known/did.json
```

### 4. Deploy to production

First configure for production:
First, push secrets to Cloudflare:

```bash
pnpm pds init --production
```

Then deploy:

# or
npm run pds init --production
yarn pds init --production
```bash
pnpm run deploy
```

This sets vars in `wrangler.jsonc` and secrets via `wrangler secret put`.
Finally, configure DNS to point your domain to the worker.

Then deploy:
## Migrating an Existing Account

To move an existing Bluesky account from bsky.social or another PDS:

### 1. Configure for migration

```bash
pnpm pds init
# Answer "Yes" when asked about migrating an existing account
```

### 2. Deploy and transfer the data

```bash
pnpm run deploy
pnpm pds migrate
```

This downloads the repository (posts, follows, likes) and all images/videos from the current PDS.

### 3. Update the identity

Follow the [AT Protocol account migration guide](https://atproto.com/guides/account-migration) to update the DID document. This requires email verification from the current PDS.

### 4. Go live

```bash
pnpm pds activate
```

The account is now live on the new PDS.

## CLI Commands

| Command | Description |
|---------|-------------|
| `pnpm pds init` | Interactive setup wizard |
| `pnpm pds init --production` | Deploy secrets to Cloudflare |
| `pnpm pds migrate` | Transfer account from source PDS |
| `pnpm pds migrate --clean` | Reset and re-import data |
| `pnpm pds activate` | Enable writes (go live) |
| `pnpm pds deactivate` | Disable writes (for re-import) |
| `pnpm pds secret key` | Generate new signing keypair |
| `pnpm pds secret jwt` | Generate new JWT secret |
| `pnpm pds secret password` | Set account password |

Add `--dev` to target your local development server instead of production.

## Configuration

Configuration uses environment variables: vars in `wrangler.jsonc` and secrets.
### Public Variables (wrangler.jsonc)

| Variable | Description |
|----------|-------------|
| `PDS_HOSTNAME` | Public hostname (e.g., pds.example.com) |
| `DID` | Account DID |
| `HANDLE` | Account handle |
| `SIGNING_KEY_PUBLIC` | Public key for DID document |

### Secrets (.dev.vars or Cloudflare)

| Variable | Description |
|----------|-------------|
| `AUTH_TOKEN` | Bearer token for API write operations |
| `SIGNING_KEY` | Private signing key |
| `JWT_SECRET` | Secret for session tokens |
| `PASSWORD_HASH` | Bcrypt hash of the account password |

## Handle Verification

Bluesky verifies control of the handle domain.

**If the handle matches the PDS hostname** (for example, both are `pds.example.com`):
- No extra setup needed. The PDS handles verification automatically.

**If the handle is on a different domain** (for example, handle `alice.example.com`, PDS at `pds.example.com`):

Add a DNS TXT record:

```
_atproto.alice.example.com TXT "did=did:web:pds.example.com"
```

Verify with:

```bash
dig TXT _atproto.alice.example.com
```

**Vars (in wrangler.jsonc):**
## Project Structure

- `PDS_HOSTNAME` - Public hostname of the PDS
- `DID` - Account DID (e.g., did:web:pds.example.com)
- `HANDLE` - Account handle (e.g., alice.example.com)
- `SIGNING_KEY_PUBLIC` - Public key for DID document (multibase)
```
├── src/
│ └── index.ts # Worker entry point (re-exports PDS)
├── wrangler.jsonc # Cloudflare Worker configuration
├── .dev.vars # Local secrets (not committed)
└── package.json
```

## Troubleshooting

**Secrets (via wrangler):**
### "PDS not responding"

- `AUTH_TOKEN` - Bearer token for API write operations
- `SIGNING_KEY` - Private signing key (secp256k1 JWK)
- `JWT_SECRET` - Secret for signing session JWTs
- `PASSWORD_HASH` - Bcrypt hash of account password (for Bluesky app login)
Ensure the worker is deployed (`pnpm run deploy`) or the dev server is running (`pnpm dev`).

## Endpoints
### "Failed to resolve handle"

Once deployed, your PDS serves:
Check the handle configuration:
- For DNS verification: ensure the TXT record has propagated (`dig TXT _atproto.yourhandle.com`)
- For same-domain handles: ensure the PDS is accessible at `https://yourdomain.com/.well-known/atproto-did`

- `GET /.well-known/did.json` - DID document
- `GET /health` - Health check
- `GET /xrpc/com.atproto.sync.getRepo` - Export repository as CAR
- `GET /xrpc/com.atproto.sync.subscribeRepos` - WebSocket firehose
- `POST /xrpc/com.atproto.repo.createRecord` - Create a record (authenticated)
- `POST /xrpc/com.atproto.repo.uploadBlob` - Upload a blob (authenticated)
- And more...
### Migration issues

If migration fails partway through:
- Run `pnpm pds migrate` again to resume from where you left off
- Use `pnpm pds migrate --clean` to start fresh (only on deactivated accounts)

## Resources

- [AT Protocol Docs](https://atproto.com)
- [AT Protocol Documentation](https://atproto.com)
- [Cloudflare Workers Docs](https://developers.cloudflare.com/workers/)
- [@ascorbic/pds on GitHub](https://github.com/ascorbic/atproto-worker)
- [@ascorbic/pds Documentation](https://github.com/ascorbic/atproto-worker/tree/main/packages/pds)
- [Account Migration Guide](https://atproto.com/guides/account-migration)

## License

MIT
Loading
Loading