A fork of the Cocoon PDS but being made more distributed.
0

Configure Feed

Select the types of activity you want to include in your feed.

1# Cocoon 2 3## Distributed version 4 5This is a fork of the Cocoon PDS with the intention of making it a distributed PDS. You can read my thoughts on why I'm trying this POC out [here](https://willdot.leaflet.pub/3miiirzf7jc2j) and follow along the series for updates. 6 7> [!WARNING] 8I migrated and have been running my main account on this PDS for months now without issue, however, I am still not responsible if things go awry, particularly during account migration. Please use caution. 9 10Cocoon is a PDS implementation in Go. It is highly experimental, and is not ready for any production use. 11 12## Quick Start with Docker Compose 13 14### Prerequisites 15 16- Docker and Docker Compose installed 17- A domain name pointing to your server (for automatic HTTPS) 18- Ports 80 and 443 open in i.e. UFW 19 20### Installation 21 221. **Clone the repository** 23 ```bash 24 git clone https://github.com/haileyok/cocoon.git 25 cd cocoon 26 ``` 27 282. **Create your configuration file** 29 ```bash 30 cp .env.example .env 31 ``` 32 333. **Edit `.env` with your settings** 34 35 Required settings: 36 ```bash 37 COCOON_DID="did:web:your-domain.com" 38 COCOON_HOSTNAME="your-domain.com" 39 COCOON_CONTACT_EMAIL="you@example.com" 40 COCOON_RELAYS="https://bsky.network" 41 42 # Generate with: openssl rand -hex 16 43 COCOON_ADMIN_PASSWORD="your-secure-password" 44 45 # Generate with: openssl rand -hex 32 46 COCOON_SESSION_SECRET="your-session-secret" 47 ``` 48 494. **Start the services** 50 ```bash 51 # Pull pre-built image from GitHub Container Registry 52 docker-compose pull 53 docker-compose up -d 54 ``` 55 56 Or build locally: 57 ```bash 58 docker-compose build 59 docker-compose up -d 60 ``` 61 62 **For PostgreSQL deployment:** 63 ```bash 64 # Add POSTGRES_PASSWORD to your .env file first! 65 docker-compose -f docker-compose.postgres.yaml up -d 66 ``` 67 685. **Get your invite code** 69 70 On first run, an invite code is automatically created. View it with: 71 ```bash 72 docker-compose logs create-invite 73 ``` 74 75 Or check the saved file: 76 ```bash 77 cat keys/initial-invite-code.txt 78 ``` 79 80 **IMPORTANT**: Save this invite code! You'll need it to create your first account. 81 826. **Monitor the services** 83 ```bash 84 docker-compose logs -f 85 ``` 86 87### What Gets Set Up 88 89The Docker Compose setup includes: 90 91- **init-keys**: Automatically generates cryptographic keys (rotation key and JWK) on first run 92- **cocoon**: The main PDS service running on port 8080 93- **create-invite**: Automatically creates an initial invite code after Cocoon starts (first run only) 94- **caddy**: Reverse proxy with automatic HTTPS via Let's Encrypt 95 96### Data Persistence 97 98The following directories will be created automatically: 99 100- `./keys/` - Cryptographic keys (generated automatically) 101 - `rotation.key` - PDS rotation key 102 - `jwk.key` - JWK private key 103 - `initial-invite-code.txt` - Your first invite code (first run only) 104- `./data/` - SQLite database and blockstore 105- Docker volumes for Caddy configuration and certificates 106 107### Optional Configuration 108 109#### Database Configuration 110 111By default, Cocoon uses SQLite which requires no additional setup. For production deployments with higher traffic, you can use PostgreSQL: 112 113```bash 114# Database type: sqlite (default) or postgres 115COCOON_DB_TYPE="postgres" 116 117# PostgreSQL connection string (required if db-type is postgres) 118# Format: postgres://user:password@host:port/database?sslmode=disable 119COCOON_DATABASE_URL="postgres://cocoon:password@localhost:5432/cocoon?sslmode=disable" 120 121# Or use the standard DATABASE_URL environment variable 122DATABASE_URL="postgres://cocoon:password@localhost:5432/cocoon?sslmode=disable" 123``` 124 125For SQLite (default): 126```bash 127COCOON_DB_TYPE="sqlite" 128COCOON_DB_NAME="/data/cocoon/cocoon.db" 129``` 130 131> **Note**: When using PostgreSQL, database backups to S3 are not handled by Cocoon. Use `pg_dump` or your database provider's backup solution instead. 132 133#### SMTP Email Settings 134```bash 135COCOON_SMTP_USER="your-smtp-username" 136COCOON_SMTP_PASS="your-smtp-password" 137COCOON_SMTP_HOST="smtp.example.com" 138COCOON_SMTP_PORT="587" 139COCOON_SMTP_EMAIL="noreply@example.com" 140COCOON_SMTP_NAME="Cocoon PDS" 141``` 142 143#### S3 Storage 144 145Cocoon supports S3-compatible storage for both database backups (SQLite only) and blob storage (images, videos, etc.): 146 147```bash 148# Enable S3 backups (SQLite databases only - hourly backups) 149COCOON_S3_BACKUPS_ENABLED=true 150 151# Enable S3 for blob storage (images, videos, etc.) 152# When enabled, blobs are stored in S3 instead of the database 153COCOON_S3_BLOBSTORE_ENABLED=true 154 155# S3 configuration (works with AWS S3, MinIO, Cloudflare R2, etc.) 156COCOON_S3_REGION="us-east-1" 157COCOON_S3_BUCKET="your-bucket" 158COCOON_S3_ENDPOINT="https://s3.amazonaws.com" 159COCOON_S3_ACCESS_KEY="your-access-key" 160COCOON_S3_SECRET_KEY="your-secret-key" 161 162# Optional: CDN/public URL for blob redirects 163# When set, com.atproto.sync.getBlob redirects to this URL instead of proxying 164COCOON_S3_CDN_URL="https://cdn.example.com" 165``` 166 167**Blob Storage Options:** 168- `COCOON_S3_BLOBSTORE_ENABLED=false` (default): Blobs stored in the database 169- `COCOON_S3_BLOBSTORE_ENABLED=true`: Blobs stored in S3 bucket under `blobs/{did}/{cid}` 170 171**Blob Serving Options:** 172- Without `COCOON_S3_CDN_URL`: Blobs are proxied through the PDS server 173- With `COCOON_S3_CDN_URL`: `getBlob` returns a 302 redirect to `{CDN_URL}/blobs/{did}/{cid}` 174 175> **Tip**: For Cloudflare R2, you can use the public bucket URL as the CDN URL. For AWS S3, you can use CloudFront or the S3 bucket URL directly if public access is enabled. 176 177### Management Commands 178 179Create an invite code: 180```bash 181docker exec cocoon-pds /cocoon create-invite-code --uses 1 182``` 183 184Reset a user's password: 185```bash 186docker exec cocoon-pds /cocoon reset-password --did "did:plc:xxx" 187``` 188 189### Updating 190 191```bash 192docker-compose pull 193docker-compose up -d 194``` 195 196## Implemented Endpoints 197 198> [!NOTE] 199Just because something is implemented doesn't mean it is finished. Tons of these are returning bad errors, don't do validation properly, etc. I'll make a "second pass" checklist at some point to do all of that. 200 201### Identity 202 203- [x] `com.atproto.identity.getRecommendedDidCredentials` 204- [x] `com.atproto.identity.requestPlcOperationSignature` 205- [x] `com.atproto.identity.resolveHandle` 206- [x] `com.atproto.identity.signPlcOperation` 207- [x] `com.atproto.identity.submitPlcOperation` 208- [x] `com.atproto.identity.updateHandle` 209 210### Repo 211 212- [x] `com.atproto.repo.applyWrites` 213- [x] `com.atproto.repo.createRecord` 214- [x] `com.atproto.repo.putRecord` 215- [x] `com.atproto.repo.deleteRecord` 216- [x] `com.atproto.repo.describeRepo` 217- [x] `com.atproto.repo.getRecord` 218- [x] `com.atproto.repo.importRepo` (Works "okay". Use with extreme caution.) 219- [x] `com.atproto.repo.listRecords` 220- [x] `com.atproto.repo.listMissingBlobs` 221 222### Server 223 224- [x] `com.atproto.server.activateAccount` 225- [x] `com.atproto.server.checkAccountStatus` 226- [x] `com.atproto.server.confirmEmail` 227- [x] `com.atproto.server.createAccount` 228- [x] `com.atproto.server.createInviteCode` 229- [x] `com.atproto.server.createInviteCodes` 230- [x] `com.atproto.server.deactivateAccount` 231- [x] `com.atproto.server.deleteAccount` 232- [x] `com.atproto.server.deleteSession` 233- [x] `com.atproto.server.describeServer` 234- [ ] `com.atproto.server.getAccountInviteCodes` 235- [x] `com.atproto.server.getServiceAuth` 236- ~~[ ] `com.atproto.server.listAppPasswords`~~ - not going to add app passwords 237- [x] `com.atproto.server.refreshSession` 238- [x] `com.atproto.server.requestAccountDelete` 239- [x] `com.atproto.server.requestEmailConfirmation` 240- [x] `com.atproto.server.requestEmailUpdate` 241- [x] `com.atproto.server.requestPasswordReset` 242- [x] `com.atproto.server.reserveSigningKey` 243- [x] `com.atproto.server.resetPassword` 244- ~~[] `com.atproto.server.revokeAppPassword`~~ - not going to add app passwords 245- [x] `com.atproto.server.updateEmail` 246 247### Sync 248 249- [x] `com.atproto.sync.getBlob` 250- [x] `com.atproto.sync.getBlocks` 251- [x] `com.atproto.sync.getLatestCommit` 252- [x] `com.atproto.sync.getRecord` 253- [x] `com.atproto.sync.getRepoStatus` 254- [x] `com.atproto.sync.getRepo` 255- [x] `com.atproto.sync.listBlobs` 256- [x] `com.atproto.sync.listRepos` 257- ~~[ ] `com.atproto.sync.notifyOfUpdate`~~ - BGS doesn't even have this implemented lol 258- [x] `com.atproto.sync.requestCrawl` 259- [x] `com.atproto.sync.subscribeRepos` 260 261### Other 262 263- [x] `com.atproto.label.queryLabels` 264- [x] `com.atproto.moderation.createReport` (Note: this should be handled by proxying, not actually implemented in the PDS) 265- [x] `app.bsky.actor.getPreferences` 266- [x] `app.bsky.actor.putPreferences` 267 268## License 269 270This project is licensed under MIT license. `server/static/pico.css` is also licensed under MIT license, available at [https://github.com/picocss/pico/](https://github.com/picocss/pico/).