Skip to content
Oeiuwq Faith Blog OpenSource Porfolio

haileyok/cocoon

An ATProtocol Personal Data Server written in Go with a SQLite block and blob store

haileyok/cocoon.json
{
"createdAt": "2025-03-23T17:50:36Z",
"defaultBranch": "main",
"description": "An ATProtocol Personal Data Server written in Go with a SQLite block and blob store",
"fullName": "haileyok/cocoon",
"homepage": "",
"language": "Go",
"name": "cocoon",
"pushedAt": "2025-11-17T18:20:50Z",
"stargazersCount": 51,
"topics": [],
"updatedAt": "2025-11-22T23:11:25Z",
"url": "https://github.com/haileyok/cocoon"
}

[!WARNING] I 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.

Cocoon is a PDS implementation in Go. It is highly experimental, and is not ready for any production use.

  • Docker and Docker Compose installed
  • A domain name pointing to your server (for automatic HTTPS)
  • Ports 80 and 443 open in i.e. UFW
  1. Clone the repository

    Terminal window
    git clone https://github.com/haileyok/cocoon.git
    cd cocoon
  2. Create your configuration file

    Terminal window
    cp .env.example .env
  3. Edit .env with your settings

    Required settings:

    Terminal window
    COCOON_DID="did:web:your-domain.com"
    COCOON_HOSTNAME="your-domain.com"
    COCOON_CONTACT_EMAIL="you@example.com"
    COCOON_RELAYS="https://bsky.network"
    # Generate with: openssl rand -hex 16
    COCOON_ADMIN_PASSWORD="your-secure-password"
    # Generate with: openssl rand -hex 32
    COCOON_SESSION_SECRET="your-session-secret"
  4. Start the services

    Terminal window
    # Pull pre-built image from GitHub Container Registry
    docker-compose pull
    docker-compose up -d

    Or build locally:

    Terminal window
    docker-compose build
    docker-compose up -d
  5. Get your invite code

    On first run, an invite code is automatically created. View it with:

    Terminal window
    docker-compose logs create-invite

    Or check the saved file:

    Terminal window
    cat keys/initial-invite-code.txt

    IMPORTANT: Save this invite code! You’ll need it to create your first account.

  6. Monitor the services

    Terminal window
    docker-compose logs -f

The Docker Compose setup includes:

  • init-keys: Automatically generates cryptographic keys (rotation key and JWK) on first run
  • cocoon: The main PDS service running on port 8080
  • create-invite: Automatically creates an initial invite code after Cocoon starts (first run only)
  • caddy: Reverse proxy with automatic HTTPS via Let’s Encrypt

The following directories will be created automatically:

  • ./keys/ - Cryptographic keys (generated automatically)
    • rotation.key - PDS rotation key
    • jwk.key - JWK private key
    • initial-invite-code.txt - Your first invite code (first run only)
  • ./data/ - SQLite database and blockstore
  • Docker volumes for Caddy configuration and certificates
Terminal window
COCOON_SMTP_USER="your-smtp-username"
COCOON_SMTP_PASS="your-smtp-password"
COCOON_SMTP_HOST="smtp.example.com"
COCOON_SMTP_PORT="587"
COCOON_SMTP_EMAIL="noreply@example.com"
COCOON_SMTP_NAME="Cocoon PDS"
Terminal window
COCOON_S3_BACKUPS_ENABLED=true
COCOON_S3_BLOBSTORE_ENABLED=true
COCOON_S3_REGION="us-east-1"
COCOON_S3_BUCKET="your-bucket"
COCOON_S3_ENDPOINT="https://s3.amazonaws.com"
COCOON_S3_ACCESS_KEY="your-access-key"
COCOON_S3_SECRET_KEY="your-secret-key"

Create an invite code:

Terminal window
docker exec cocoon-pds /cocoon create-invite-code --uses 1

Reset a user’s password:

Terminal window
docker exec cocoon-pds /cocoon reset-password --did "did:plc:xxx"
Terminal window
docker-compose pull
docker-compose up -d

[!NOTE] Just 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.

  • com.atproto.identity.getRecommendedDidCredentials
  • com.atproto.identity.requestPlcOperationSignature
  • com.atproto.identity.resolveHandle
  • com.atproto.identity.signPlcOperation
  • com.atproto.identity.submitPlcOperation
  • com.atproto.identity.updateHandle
  • com.atproto.repo.applyWrites
  • com.atproto.repo.createRecord
  • com.atproto.repo.putRecord
  • com.atproto.repo.deleteRecord
  • com.atproto.repo.describeRepo
  • com.atproto.repo.getRecord
  • com.atproto.repo.importRepo (Works “okay”. Use with extreme caution.)
  • com.atproto.repo.listRecords
  • com.atproto.repo.listMissingBlobs
  • com.atproto.server.activateAccount
  • com.atproto.server.checkAccountStatus
  • com.atproto.server.confirmEmail
  • com.atproto.server.createAccount
  • com.atproto.server.createInviteCode
  • com.atproto.server.createInviteCodes
  • com.atproto.server.deactivateAccount
  • com.atproto.server.deleteAccount
  • com.atproto.server.deleteSession
  • com.atproto.server.describeServer
  • com.atproto.server.getAccountInviteCodes
  • com.atproto.server.getServiceAuth
  • [ ] com.atproto.server.listAppPasswords - not going to add app passwords
  • com.atproto.server.refreshSession
  • com.atproto.server.requestAccountDelete
  • com.atproto.server.requestEmailConfirmation
  • com.atproto.server.requestEmailUpdate
  • com.atproto.server.requestPasswordReset
  • com.atproto.server.reserveSigningKey
  • com.atproto.server.resetPassword
  • [] com.atproto.server.revokeAppPassword - not going to add app passwords
  • com.atproto.server.updateEmail
  • com.atproto.sync.getBlob
  • com.atproto.sync.getBlocks
  • com.atproto.sync.getLatestCommit
  • com.atproto.sync.getRecord
  • com.atproto.sync.getRepoStatus
  • com.atproto.sync.getRepo
  • com.atproto.sync.listBlobs
  • com.atproto.sync.listRepos
  • [ ] com.atproto.sync.notifyOfUpdate - BGS doesn’t even have this implemented lol
  • com.atproto.sync.requestCrawl
  • com.atproto.sync.subscribeRepos
  • com.atproto.label.queryLabels
  • com.atproto.moderation.createReport (Note: this should be handled by proxying, not actually implemented in the PDS)
  • app.bsky.actor.getPreferences
  • app.bsky.actor.putPreferences

This project is licensed under MIT license. server/static/pico.css is also licensed under MIT license, available at https://github.com/picocss/pico/.