Alternative ATProto PDS implementation
1# ATProto PDS
2```
3 __ __
4 /\ \__ /\ \__
5 __ \ \ ,_\ _____ _ __ ___\ \ ,_\ ___
6 /'__'\ \ \ \/ /\ '__'\/\''__\/ __'\ \ \/ / __'\
7 /\ \L\.\_\ \ \_\ \ \L\ \ \ \//\ \L\ \ \ \_/\ \L\ \
8 \ \__/.\_\\ \__\\ \ ,__/\ \_\\ \____/\ \__\ \____/
9 \/__/\/_/ \/__/ \ \ \/ \/_/ \/___/ \/__/\/___/
10 \ \_\
11 \/_/
12```
13
14This is an implementation of an ATProto PDS, built with [Axum](https://github.com/tokio-rs/axum), [rsky](https://github.com/blacksky-algorithms/rsky/) and [Atrium](https://github.com/sugyan/atrium).
15This PDS implementation uses a SQLite database and [diesel.rs](https://diesel.rs/) ORM to store canonical user data, and file system storage to store user blobs.
16
17Heavily inspired by David Buchanan's [millipds](https://github.com/DavidBuchanan314/millipds).
18This implementation forked from [DrChat/bluepds](https://github.com/DrChat/bluepds), and now makes heavy use of the [rsky-repo](https://github.com/blacksky-algorithms/rsky/tree/main/rsky-repo) repository implementation.
19The `actor_store` and `account_manager` modules have been reimplemented from [rsky-pds](https://github.com/blacksky-algorithms/rsky/tree/main/rsky-pds) to use a SQLite backend and file storage, which are themselves adapted from the [original Bluesky implementation](https://github.com/bluesky-social/atproto) using SQLite in Typescript.
20
21
22If you want to see this fork in action, there is a live account hosted by this PDS at [@teq.shatteredsky.net](https://bsky.app/profile/teq.shatteredsky.net)!
23
24> [!WARNING]
25> This PDS is undergoing heavy development, and this branch is not at an operable release. Do _NOT_ use this to host your primary account or any important data!
26
27## Quick Start
28```
29cargo run
30```
31
32## Cost breakdown (on Oracle Cloud Infrastructure)
33This is how much it costs to host the @teq.shatteredsky.net account:
34
35- $0/mo [Always Free Resources](https://docs.oracle.com/en-us/iaas/Content/FreeTier/freetier_topic-Always_Free_Resources.htm)
36 - $0/mo: VM.Standard.A1.Flex
37 - OCPU count: 2
38 - Network bandwidth: 2 Gbps
39 - Memory: 12 GB
40 - $0/mo: Virtual Cloud Network
41 - IPv4 address
42 - IPv6 address
43 - $0/mo: Boot volume
44 - Size: 47 GB
45 - VPUs/GB: 10
46
47This is about half of the 3,000 OCPU hours and 18,000 GB hours available per month for free on the VM.Standard.A1.Flex shape. This is _without_ optimizing for costs. The PDS can likely be made to run on much less resources.
48
49## To-do
50### APIs
51- [ ] [Service proxying](https://atproto.com/specs/xrpc#service-proxying)
52- [ ] UG /xrpc/_health (undocumented, but impl by reference PDS)
53<!-- - [ ] xx /xrpc/app.bsky.notification.registerPush
54- app.bsky.actor
55 - [ ] AG /xrpc/app.bsky.actor.getPreferences
56 - [ ] xx /xrpc/app.bsky.actor.getProfile
57 - [ ] xx /xrpc/app.bsky.actor.getProfiles
58 - [ ] AP /xrpc/app.bsky.actor.putPreferences
59- app.bsky.feed
60 - [ ] xx /xrpc/app.bsky.feed.getActorLikes
61 - [ ] xx /xrpc/app.bsky.feed.getAuthorFeed
62 - [ ] xx /xrpc/app.bsky.feed.getFeed
63 - [ ] xx /xrpc/app.bsky.feed.getPostThread
64 - [ ] xx /xrpc/app.bsky.feed.getTimeline -->
65- com.atproto.admin
66 - [ ] xx /xrpc/com.atproto.admin.deleteAccount
67 - [ ] xx /xrpc/com.atproto.admin.disableAccountInvites
68 - [ ] xx /xrpc/com.atproto.admin.disableInviteCodes
69 - [ ] xx /xrpc/com.atproto.admin.enableAccountInvites
70 - [ ] xx /xrpc/com.atproto.admin.getAccountInfo
71 - [ ] xx /xrpc/com.atproto.admin.getAccountInfos
72 - [ ] xx /xrpc/com.atproto.admin.getInviteCodes
73 - [ ] xx /xrpc/com.atproto.admin.getSubjectStatus
74 - [ ] xx /xrpc/com.atproto.admin.sendEmail
75 - [ ] xx /xrpc/com.atproto.admin.updateAccountEmail
76 - [ ] xx /xrpc/com.atproto.admin.updateAccountHandle
77 - [ ] xx /xrpc/com.atproto.admin.updateAccountPassword
78 - [ ] xx /xrpc/com.atproto.admin.updateSubjectStatus
79- com.atproto.identity
80 - [ ] xx /xrpc/com.atproto.identity.getRecommendedDidCredentials
81 - [ ] AP /xrpc/com.atproto.identity.requestPlcOperationSignature
82 - [ ] UG /xrpc/com.atproto.identity.resolveHandle
83 - [ ] AP /xrpc/com.atproto.identity.signPlcOperation
84 - [ ] xx /xrpc/com.atproto.identity.submitPlcOperation
85 - [ ] AP /xrpc/com.atproto.identity.updateHandle
86<!-- - com.atproto.moderation
87 - [ ] xx /xrpc/com.atproto.moderation.createReport -->
88- com.atproto.repo
89 - [X] AP /xrpc/com.atproto.repo.applyWrites
90 - [X] AP /xrpc/com.atproto.repo.createRecord
91 - [X] AP /xrpc/com.atproto.repo.deleteRecord
92 - [X] UG /xrpc/com.atproto.repo.describeRepo
93 - [X] UG /xrpc/com.atproto.repo.getRecord
94 - [X] xx /xrpc/com.atproto.repo.importRepo
95 - [X] xx /xrpc/com.atproto.repo.listMissingBlobs
96 - [X] UG /xrpc/com.atproto.repo.listRecords
97 - [X] AP /xrpc/com.atproto.repo.putRecord
98 - [X] AP /xrpc/com.atproto.repo.uploadBlob
99- com.atproto.server
100 - [ ] xx /xrpc/com.atproto.server.activateAccount
101 - [ ] xx /xrpc/com.atproto.server.checkAccountStatus
102 - [ ] xx /xrpc/com.atproto.server.confirmEmail
103 - [ ] UP /xrpc/com.atproto.server.createAccount
104 - [ ] xx /xrpc/com.atproto.server.createAppPassword
105 - [ ] AP /xrpc/com.atproto.server.createInviteCode
106 - [ ] xx /xrpc/com.atproto.server.createInviteCodes
107 - [ ] UP /xrpc/com.atproto.server.createSession
108 - [ ] xx /xrpc/com.atproto.server.deactivateAccount
109 - [ ] xx /xrpc/com.atproto.server.deleteAccount
110 - [ ] xx /xrpc/com.atproto.server.deleteSession
111 - [ ] UG /xrpc/com.atproto.server.describeServer
112 - [ ] xx /xrpc/com.atproto.server.getAccountInviteCodes
113 - [ ] AG /xrpc/com.atproto.server.getServiceAuth
114 - [ ] AG /xrpc/com.atproto.server.getSession
115 - [ ] xx /xrpc/com.atproto.server.listAppPasswords
116 - [ ] xx /xrpc/com.atproto.server.refreshSession
117 - [ ] xx /xrpc/com.atproto.server.requestAccountDelete
118 - [ ] xx /xrpc/com.atproto.server.requestEmailConfirmation
119 - [ ] xx /xrpc/com.atproto.server.requestEmailUpdate
120 - [ ] xx /xrpc/com.atproto.server.requestPasswordReset
121 - [ ] xx /xrpc/com.atproto.server.reserveSigningKey
122 - [ ] xx /xrpc/com.atproto.server.resetPassword
123 - [ ] xx /xrpc/com.atproto.server.revokeAppPassword
124 - [ ] xx /xrpc/com.atproto.server.updateEmail
125- com.atproto.sync
126 - [ ] UG /xrpc/com.atproto.sync.getBlob
127 - [ ] UG /xrpc/com.atproto.sync.getBlocks
128 - [ ] UG /xrpc/com.atproto.sync.getLatestCommit
129 - [ ] UG /xrpc/com.atproto.sync.getRecord
130 - [ ] UG /xrpc/com.atproto.sync.getRepo
131 - [ ] UG /xrpc/com.atproto.sync.getRepoStatus
132 - [ ] UG /xrpc/com.atproto.sync.listBlobs
133 - [ ] UG /xrpc/com.atproto.sync.listRepos
134 - [ ] UG /xrpc/com.atproto.sync.subscribeRepos
135
136## Deployment (NixOS)
137```nix
138{
139 inputs = {
140 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
141 bluepds = {
142 url = "github:Teqed/bluesky-pds";
143 };
144 };
145 outputs = {
146 nixpkgs,
147 bluepds,
148 ...
149 }: {
150 nixosConfigurations.mysystem = nixpkgs.lib.nixosSystem {
151 modules = [
152 ({ pkgs, ... }: {
153 config.services.bluepds = {
154 enable = true;
155 host_name = "pds.example.com";
156 listen_address = "0.0.0.0:8000";
157 test = "true"; # Set to false for production
158 };
159 })
160 ];
161 };
162 };
163}
164```