Bluesky PDS#
__ __
/\ \__ /\ \__
__ \ \ ,_\ _____ _ __ ___\ \ ,_\ ___
/'__'\ \ \ \/ /\ '__'\/\''__\/ __'\ \ \/ / __'\
/\ \L\.\_\ \ \_\ \ \L\ \ \ \//\ \L\ \ \ \_/\ \L\ \
\ \__/.\_\\ \__\\ \ ,__/\ \_\\ \____/\ \__\ \____/
\/__/\/_/ \/__/ \ \ \/ \/_/ \/___/ \/__/\/___/
\ \_\
\/_/
This is an implementation of an ATProto PDS, built with Axum and Atrium. Heavily inspired by David Buchanan's millipds. This implementation forked from the azure-rust-app starter template.
This PDS implementation uses a SQLite database to store private account information and file storage to store canonical user data.
If you want to see this PDS in action, there is a live account hosted by this PDS at @test.justinm.one!
WARNING
This PDS is undergoing heavy development. Do NOT use this to host your primary account or any important data!
Quick Start#
cargo run
Cost breakdown (on Azure)#
This is how much it costs to host the @test.justinm.one account:
- $20/mo
- $13/mo: Azure Application Service
- $5/mo: Azure Container Registry
- $1/mo: Azure Storage Account
This is without optimizing for costs. The PDS can likely be made much cheaper.
Code map#
* migrations/ - SQLite database migrations
* src/
* endpoints/ - ATProto API endpoints
* auth.rs - Authentication primitives
* config.rs - Application configuration
* did.rs - Decentralized Identifier helpers
* error.rs - Axum error helpers
* firehose.rs - ATProto firehose producer
* main.rs - Main entrypoint
* metrics.rs - Definitions for telemetry instruments
* oauth.rs - OAuth routes
* plc.rs - Functionality to access the Public Ledger of Credentials
* storage.rs - Helpers to access user repository storage
To-do#
Teqed's#
- OAuth
-
/.well-known/oauth-protected-resource- Authorization Server Metadata -
/.well-known/oauth-authorization-server -
/par- Pushed Authorization Request -
/client-metadata.json- Client metadata discovery -
/oauth/authorize -
/oauth/authorize/sign-in -
/oauth/token
-
- Email verification
- 2FA
- Admin endpoints
- App passwords
-
listRecordsfixes- Fix collection prefixing (terminate with
/) - Fix cursor handling (return
cidinstead ofkey)
- Fix collection prefixing (terminate with
- Session management (JWT)
- Match token fields to reference implementation
- RefreshSession from Bluesky Client
- Respond with JSON error message
ExpiredToken
- Respond with JSON error message
- Cursor handling
- Implement time-based unix microsecond sequences
- Startup with present cursor
- Respond
RecordNotFound, required for:- app.bsky.feed.postgate
- app.bsky.feed.threadgate
- app.bsky... (profile creation?)
- Linting
- Rustfmt
- warnings
- deprecated-safe
- future-incompatible
- keyword-idents
- let-underscore
- nonstandard-style
- refining-impl-trait
- rust-2018-idioms
- rust-2018/2021/2024-compatibility
- ungrouped
- Clippy
- nursery
- correctness
- suspicious
- complexity
- perf
- style
- pedantic
- cargo
- ungrouped
- Rustfmt
High-level features#
- Authentication
- Storage backend abstractions
- Azure blob storage backend
- Backblaze b2(?)
- Telemetry
- Metrics (counters/gauges/etc)
- Exporters for common backends (Prometheus/etc)
APIs#
- Service proxying
- UG /xrpc/_health (undocumented, but impl by reference PDS)
- com.atproto.admin
- xx /xrpc/com.atproto.admin.deleteAccount
- xx /xrpc/com.atproto.admin.disableAccountInvites
- xx /xrpc/com.atproto.admin.disableInviteCodes
- xx /xrpc/com.atproto.admin.enableAccountInvites
- xx /xrpc/com.atproto.admin.getAccountInfo
- xx /xrpc/com.atproto.admin.getAccountInfos
- xx /xrpc/com.atproto.admin.getInviteCodes
- xx /xrpc/com.atproto.admin.getSubjectStatus
- xx /xrpc/com.atproto.admin.sendEmail
- xx /xrpc/com.atproto.admin.updateAccountEmail
- xx /xrpc/com.atproto.admin.updateAccountHandle
- xx /xrpc/com.atproto.admin.updateAccountPassword
- xx /xrpc/com.atproto.admin.updateSubjectStatus
- com.atproto.identity
- xx /xrpc/com.atproto.identity.getRecommendedDidCredentials
- AP /xrpc/com.atproto.identity.requestPlcOperationSignature
- UG /xrpc/com.atproto.identity.resolveHandle
- AP /xrpc/com.atproto.identity.signPlcOperation
- xx /xrpc/com.atproto.identity.submitPlcOperation
- AP /xrpc/com.atproto.identity.updateHandle
- com.atproto.repo
- AP /xrpc/com.atproto.repo.applyWrites
- AP /xrpc/com.atproto.repo.createRecord
- AP /xrpc/com.atproto.repo.deleteRecord
- UG /xrpc/com.atproto.repo.describeRepo
- UG /xrpc/com.atproto.repo.getRecord
- xx /xrpc/com.atproto.repo.importRepo
- xx /xrpc/com.atproto.repo.listMissingBlobs
- UG /xrpc/com.atproto.repo.listRecords
- AP /xrpc/com.atproto.repo.putRecord
- AP /xrpc/com.atproto.repo.uploadBlob
- com.atproto.server
- xx /xrpc/com.atproto.server.activateAccount
- xx /xrpc/com.atproto.server.checkAccountStatus
- xx /xrpc/com.atproto.server.confirmEmail
- UP /xrpc/com.atproto.server.createAccount
- xx /xrpc/com.atproto.server.createAppPassword
- AP /xrpc/com.atproto.server.createInviteCode
- xx /xrpc/com.atproto.server.createInviteCodes
- UP /xrpc/com.atproto.server.createSession
- xx /xrpc/com.atproto.server.deactivateAccount
- xx /xrpc/com.atproto.server.deleteAccount
- xx /xrpc/com.atproto.server.deleteSession
- UG /xrpc/com.atproto.server.describeServer
- xx /xrpc/com.atproto.server.getAccountInviteCodes
- AG /xrpc/com.atproto.server.getServiceAuth
- AG /xrpc/com.atproto.server.getSession
- xx /xrpc/com.atproto.server.listAppPasswords
- xx /xrpc/com.atproto.server.refreshSession
- xx /xrpc/com.atproto.server.requestAccountDelete
- xx /xrpc/com.atproto.server.requestEmailConfirmation
- xx /xrpc/com.atproto.server.requestEmailUpdate
- xx /xrpc/com.atproto.server.requestPasswordReset
- xx /xrpc/com.atproto.server.reserveSigningKey
- xx /xrpc/com.atproto.server.resetPassword
- xx /xrpc/com.atproto.server.revokeAppPassword
- xx /xrpc/com.atproto.server.updateEmail
- com.atproto.sync
- UG /xrpc/com.atproto.sync.getBlob
- UG /xrpc/com.atproto.sync.getBlocks
- UG /xrpc/com.atproto.sync.getLatestCommit
- UG /xrpc/com.atproto.sync.getRecord
- UG /xrpc/com.atproto.sync.getRepo
- UG /xrpc/com.atproto.sync.getRepoStatus
- UG /xrpc/com.atproto.sync.listBlobs
- UG /xrpc/com.atproto.sync.listRepos
- UG /xrpc/com.atproto.sync.subscribeRepos
Quick Deployment (Azure CLI)#
az group create --name "webapp" --location southcentralus
az deployment group create --resource-group "webapp" --template-file .\deployment.bicep --parameters webAppName=testapp
az acr login --name <insert name of ACR resource here>
docker build -t <ACR>.azurecr.io/testapp:latest .
docker push <ACR>.azurecr.io/testapp:latest
Quick Deployment (NixOS)#
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
bluepds = {
url = "github:Teqed/bluesky-pds";
};
};
outputs = {
nixpkgs,
bluepds,
...
}: {
nixosConfigurations.mysystem = nixpkgs.lib.nixosSystem {
modules = [
({ pkgs, ... }: {
config.services.bluepds = {
enable = true;
host_name = "pds.example.com";
listen_address = "0.0.0.0:8000";
test = "true"; # Set to false for production
};
})
];
};
};
}