Skip to content

Create the first account

Sign-up needs an invite code, so that strangers cannot fill the server. The admin password creates codes.

On the host, with PDS_ADMIN_PASSWORD from pds.env in the environment:

Terminal window
curl -s -u "admin:$PDS_ADMIN_PASSWORD" -H 'content-type: application/json' -d '{"useCount": 1}' https://pds.example.com/xrpc/com.atproto.server.createInviteCode

It answers {"code":"pds-example-com-xxxxx-xxxxx"}. A code with a useCount of 5 admits five accounts.

  1. Open the app and choose Create account.
  2. Under Hosting provider, choose Custom and enter https://pds.example.com.
  3. Enter the invite code, an email address, a password and a handle. The handle becomes alice.pds.example.com.
  4. Post something.

The first request for alice.pds.example.com makes Caddy fetch its certificate, which takes a few seconds.

Terminal window
curl -s -H 'content-type: application/json' -d '{"email":"alice@example.com","handle":"alice.pds.example.com","password":"…","inviteCode":"pds-example-com-xxxxx-xxxxx"}' https://pds.example.com/xrpc/com.atproto.server.createAccount

The answer holds the account’s did, its handle and a session. Sign in with the handle and the password from any app.

Terminal window
curl -s https://alice.pds.example.com/.well-known/atproto-did

It prints the account’s DID, did:plc:…. Apps resolve handles this way.

A post appears in other people’s timelines once the relay at bsky.network crawls the host. The server asks it to with the first write after a start, and then at most once in twenty minutes. The relay’s own status shows the connection:

Terminal window
curl -s "https://bsky.network/xrpc/com.atproto.sync.getHostStatus?hostname=pds.example.com"

The answer has "status":"active" and a seq that moves with each write.

Next: set up email so that confirmation and password-reset mail arrives, and back up the data directory and pds.env.