Vow#
WARNING
This is highly experimental software. Use with caution, especially during account migration.
Vow is a PDS (Personal Data Server) implementation in Go for the AT Protocol.
Incoming Features#
- BYOK (Bring Your Own Key) for PDS — users supply their own signing key for their PDS, keeping full custody of their identity.
- IPFS for account storage — repository data is stored on IPFS, giving users a decentralised and portable data layer.
- x402 payments for IPFS storage — IPFS pinning costs are settled via x402, paid directly by the user. The payment key is derived from the user's EVM wallet, so no separate key management is required.
- Extension for action signing — a browser extension intercepts each write operation sent to the user's PDS and prompts the user to sign it locally, so private keys never leave the client.
Quick Start with Docker Compose#
Prerequisites#
- Docker and Docker Compose installed
- A domain name pointing to your server
- Ports 80 and 443 open
Installation#
-
Clone the repository
git clone https://pkg.rbrt.fr/vow.git cd vow -
Create your configuration file
cp .env.example .env -
Edit
.envwith your settingsVOW_DID="did:web:your-domain.com" VOW_HOSTNAME="your-domain.com" VOW_CONTACT_EMAIL="you@example.com" VOW_RELAYS="https://bsky.network" # Generate with: openssl rand -hex 16 VOW_ADMIN_PASSWORD="your-secure-password" # Generate with: openssl rand -hex 32 VOW_SESSION_SECRET="your-session-secret" -
Start the services
docker-compose pull docker-compose up -d -
Get your invite code
On first run, an invite code is automatically created. View it with:
docker-compose logs create-inviteOr check the saved file:
cat keys/initial-invite-code.txt -
Monitor the services
docker-compose logs -f
What Gets Set Up#
- init-keys: Generates cryptographic keys (rotation key and JWK) on first run
- vow: The main PDS service running on port 8080
- create-invite: Creates an initial invite code on first run
Data Persistence#
./keys/— Cryptographic keys (generated automatically)rotation.key— PDS rotation keyjwk.key— JWK private keyinitial-invite-code.txt— Your first invite code (first run only)
./data/— SQLite database and blockstore
Configuration#
Database#
Vow uses SQLite by default. No additional setup required.
VOW_DB_NAME="/data/vow/vow.db"
SMTP Email#
VOW_SMTP_USER="your-smtp-username"
VOW_SMTP_PASS="your-smtp-password"
VOW_SMTP_HOST="smtp.example.com"
VOW_SMTP_PORT="587"
VOW_SMTP_EMAIL="noreply@example.com"
VOW_SMTP_NAME="Vow PDS"
IPFS Blob Storage#
By default blobs are stored in SQLite. Optionally, blobs can be stored on IPFS via a local Kubo node:
VOW_IPFS_BLOBSTORE_ENABLED=true
# URL of the local Kubo RPC API (default: http://127.0.0.1:5001)
VOW_IPFS_NODE_URL="http://127.0.0.1:5001"
# Optional: redirect getBlob to a public gateway instead of proxying
VOW_IPFS_GATEWAY_URL="https://ipfs.io"
# Optional: remote pinning service
VOW_IPFS_PINNING_SERVICE_URL="https://api.pinata.cloud/psa"
VOW_IPFS_PINNING_SERVICE_TOKEN="your-token"
Management Commands#
Create an invite code:
docker exec vow-pds /vow create-invite-code --uses 1
Reset a user's password:
docker exec vow-pds /vow reset-password --did "did:plc:xxx"
Updating#
docker-compose pull
docker-compose up -d
Implemented Endpoints#
NOTE
Just because something is implemented doesn't mean it is finished. Many endpoints still have rough edges around validation and error handling.
Identity#
-
com.atproto.identity.getRecommendedDidCredentials -
com.atproto.identity.requestPlcOperationSignature -
com.atproto.identity.resolveHandle -
com.atproto.identity.signPlcOperation -
com.atproto.identity.submitPlcOperation -
com.atproto.identity.updateHandle
Repo#
-
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
Server#
-
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.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.updateEmail
Sync#
-
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.requestCrawl -
com.atproto.sync.subscribeRepos
Other#
-
com.atproto.label.queryLabels -
com.atproto.moderation.createReport -
app.bsky.actor.getPreferences -
app.bsky.actor.putPreferences
License#
MIT. server/static/pico.css is also MIT licensed, available at https://github.com/picocss/pico/.
Thanks#
Vow is based on Cocoon. Many thanks for the solid foundation.
Vow vs Cocoon#
| Feature | Vow | Cocoon |
|---|---|---|
| Language | Go | Go |
| SQLite blockstore | ✅ | ✅ |
| PostgreSQL support | ❌ removed | ✅ |
| S3 blob storage | ❌ removed | ✅ |
| S3 database backups | ❌ removed | ✅ |
| IPFS blob storage | ✅ (Kubo) | ❌ |
| IPFS account storage | 🔜 incoming | ❌ |
| BYOK (Bring Your Own Key) | 🔜 incoming | ❌ |
| x402 payments for IPFS | 🔜 incoming | ❌ |
| Extension for action signing | 🔜 incoming | ❌ |
Vow trades Cocoon's operational storage flexibility (PostgreSQL, S3) for a leaner SQLite-only core, with a roadmap focused on decentralised storage and user-controlled keys.