Table of Contents

Setting up a local PDS Server

Completed on Digital Ocean Ubuntu 22.04 droplet running nginx and letsencrypt.

Install PDS

The installer assumes ports 80 and 443 are available and launches a Docker instance of Caddy to serve. This will conflict with NGINX but the installer still gets us started:

wget https://raw.githubusercontent.com/bluesky-social/pds/main/installer.sh
sudo bash installer.sh

You'll see from your list of Docker instances that Caddy didn't start OK. Kill all the instances related to PDS by listing them, stopping them, then removing them:

docker ps
docker stop <instance>
docker rm <instance>

To get things to work correctly we are going to need to replace compose.yaml with something that doesn't start Caddy. Here's a modification of the one found here. For a standard install you'll put compose.yaml in /pds

version: '3.9'
services:
  pds:
    container_name: pds
    image: ghcr.io/bluesky-social/pds:0.4
    restart: unless-stopped
    volumes:
      - type: bind
        source: /pds
        target: /pds
    ports:
      - '3000:3000'
    env_file:
      - /pds/pds.envroot@togettech-main:/pds
wget http://localhost:3000/xrpc/_health

should return something close to:{"version":"0.4.74"}

Get email working for pdsadmin

PDS_EMAIL_SMTP_URL=smtps://<SES USER>:<SES PW>@email-smtp.us-east-2.amazonaws.com:465/ # change AWS email server as needed
PDS_EMAIL_FROM_ADDRESS=<YOUR EMAIL ADDRESS>

Get NGINX reverse proxy working

In /etc/nginx/sites-available create a file (could be named pds):

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

server {
    server_name <YOUR DOMAIN NAME HERE. COULD HAVE SUBDOMAIN. EXAMPLE: pds.johnharrison.cc>;

    location /xrpc {
        proxy_pass http://localhost:3000;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Host            $host;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }

    location /.well-known/atproto-did {
        proxy_pass http://localhost:3000/.well-known/atproto-did;
        proxy_set_header Host            $host;
    }
wget https://<YOUR DOMAIN>/xrpc/_health

should return something close to:{"version":"0.4.74"}

wsdump "wss://example.com/xrpc/com.atproto.sync.subscribeRepos?cursor=0"

If you don't see an error such as unauthorized it's probably working. There won't be much output yet. If it's not working, it's a problem in your Nginx config

Migrating existing account from Bluesky's PDS to the local PDS

This requires a Go app called Goat which is provided by Bluesky. This can be installed on any machine i.e. it doesn't have to be installed on the local PDS

wget https://go.dev/dl/go-INSERT_CURRENT_VERSION_HERE.linux-amd64.tar.gz
sudo tar -C /usr/local -xvf goINSERT_CURRENT_VERSION_HERE.linux-amd64.tar.gz
echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.profile
source ~/.profile
go version # verify it's working
git clone https://github.com/bluesky-social/indigo
go build ./cmd/goat
sudo cp goat /usr/local/bin
goat --version # confirm it's working
goat account login -u $OLDHANDLE -p $OLDPASSWORD''
goat account plc request-token
# format
goat account migrate \
    --pds-host $NEWPDSHOST \
    --new-handle $NEWHANDLE \
    --new-password $NEWPASSWORD \
    --new-email $NEWEMAIL \
    --plc-token $NEWPLCTOKEN \
    --invite-code $INVITECODE

# example
goat account migrate \
    --pds-host https://blueskydemo.hyprlab.co \
    --new-handle jasondemo.blueskydemo.hyprlab.co \
    --new-password tPVQ9oRLwfAqq7gz \
    --new-email servers@hyprlab.co \
    --plc-token QUCDK-SHTBV \
    --invite-code blueskydemo-hyprlab-co-lz3di-wlsvy
pdsadmin account list
pdsadmin account delete $YOURDID

Get bsky.app to recognize your local PDS

At this point my profile showed “invalid handle.” To fix:

References