Using docker and curl to do the first steps of what could be creating an atproto app.
The Bluesky Personal Data Server (PDS) comes with instructions and automation for taking over a server and running a node connected to bsky.app, but I wanted to run a local disconnected PDS so I just muck around with creating fake users and posting data as if I was creating a new atproto app.
Inside their system is a docker container, and we can run that by itself:
docker image pull ghcr.io/bluesky-social/pds:latest
You'll probably want data somewhere other than /tmp
mkdir -p /tmp/pdsdata/blocks
PDS_ADMIN_PASSWORD=$(openssl rand --hex 16)PDS_JWT_SECRET=$(openssl rand --hex 16)PLC_ROTATION_KEY=$(openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32)PDS_DATADIR=/tmp/pdsdataPDS_HOSTNAME=foo.bar.comcat<<EOF >/tmp/pdsdata/pds.envPDS_HOSTNAME=${PDS_HOSTNAME}PDS_JWT_SECRET=${PDS_JWT_SECRET}PDS_ADMIN_PASSWORD=${PDS_ADMIN_PASSWORD}PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=${PLC_ROTATION_KEY}PDS_DATA_DIRECTORY=/pdsPDS_BLOBSTORE_DISK_LOCATION=/pds/blocksPDS_DID_PLC_URL=https://plc.directoryPDS_BSKY_APP_VIEW_URL=https://api.bsky.appPDS_BSKY_APP_VIEW_DID=did:web:api.bsky.appPDS_REPORT_SERVICE_URL=https://mod.bsky.appPDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndacPDS_CRAWLERS=https://bsky.networkLOG_ENABLED=trueNODE_ENV=developmentEOFdocker run -d --name pds --restart=unless-stopped --network=host -v /b2/bolson/Bluesky/pdsdata:/pds --env-file=/b2/bolson/Bluesky/pdsdata/pds.env ghcr.io/bluesky-social/pds:latest
curl -L 'http://localhost:3000/xrpc/com.atproto.sync.listRepos?limit=100'curl -L 'http://localhost:3000/xrpc/com.atproto.server.describeServer'
curl -L -X POST 'http://localhost:3000/xrpc/com.atproto.server.createInviteCode' --user "admin:${PDS_ADMIN_PASSWORD}" --data-raw '{"useCount":1}' -H 'Content-Type: application/json'
curl -L -X POST 'http://localhost:3000/xrpc/com.atproto.server.createAccount' \-H 'Content-Type: application/json' \-H 'Accept: application/json' \--user "admin:${PDS_ADMIN_PASSWORD}" \--data-raw '{"handle": "bob2.foo.bar.com","inviteCode":"foo-bar-com-zx6uq-cjkle","email":"bob2@foo.bar.com","password":"hunter2"}'
This returns a bunch of json about the created user, the parts we need for next steps are "did" and "accesJwt", like:
"did":"did:plc:ks35mpkznuqalfrr3drm7tfu", "accessJwt":"eyJhbGciOiJIUzI1NiJ9.eyJzY29wZSI6ImNvbS5hdHByb3RvLmFjY2VzcyIsImF1ZCI6ImRpZDp3ZWI6ZG8uYm9sc29uLm9yZyIsInN1YiI6ImRpZDpwbGM6a3MzNW1wa3pudXFhbGZycjNkcm03dGZ1IiwiaWF0IjoxNzI0NDI3NTk0LCJleHAiOjE3MjQ0MzQ3OTR9._uG-PTAqNLQT7PqohWFv-0lvyQtz_ud5XOwCqnjDPqs"
Let's put that in shell to make the next commands nicer
ACCESS_JWT="eyJhbGciOiJIUzI1NiJ9.eyJzY29wZSI6ImNvbS5hdHByb3RvLmFjY2VzcyIsImF1ZCI6ImRpZDp3ZWI6ZG8uYm9sc29uLm9yZyIsInN1YiI6ImRpZDpwbGM6a3MzNW1wa3pudXFhbGZycjNkcm03dGZ1IiwiaWF0IjoxNzI0NDI3NTk0LCJleHAiOjE3MjQ0MzQ3OTR9._uG-PTAqNLQT7PqohWFv-0lvyQtz_ud5XOwCqnjDPqs"
The first couple 'admin' APIs used HTTP user:password with the user as 'admin' and the password set for the whole server in setup back in pds.env. Later actions as a user put the access JWT blob into the Authorization header.
Post a record! (note validate=false because I'm not posting proper lexicon data)
curl -L -X POST 'http://localhost:3000/xrpc/com.atproto.repo.createRecord' \-H 'Content-Type: application/json' \-H 'Accept: application/json' \-H 'Authorization: Bearer '${ACCESS_JWT} \--data-raw '{"repo":"did:plc:ks35mpkznuqalfrr3drm7tfu","collection":"com.bar.wat","rkey":"aoeustnh1234098","validate":false,"record":{"a":"foo","b":1234}}'
curl -L 'http://localhost:3000/xrpc/com.atproto.repo.listRecords?repo=did:plc:ks35mpkznuqalfrr3drm7tfu&collection=org.bolson.vote'