Skip to content

Instantly share code, notes, and snippets.

@tdack
Last active January 31, 2025 07:15
Show Gist options
  • Save tdack/3608853b66220d9defd8b045be52d136 to your computer and use it in GitHub Desktop.
Save tdack/3608853b66220d9defd8b045be52d136 to your computer and use it in GitHub Desktop.
AT Protocol (Bluesky) Personal Data Server (PDS) Docker compose

AT Proto (BlueSky) Personal Data Server Docker Compose File

This Docker compose.yml will allow you to run your own AT Proto server that can interact with the BlueSky app and social network.

The installer from https://github.com/bluesky-social/pds is designed for a clean virtual host and will take over the entire machine to run the PDS. This compose.yml file will allow you to run it on your own machine (eg: a Raspberry Pi) whilst running other services/applications.

Once the image is running following continue following the instructions linked above to create your first user and log in.

Note: You might need to touch /opt/pds/pds.env and restart the stack if things don't seem to be working.

SSL/TLS Certificates

Setting up the PDS in this way will require you to manage your own SSL/TLS certificates for the domain (*.example.com). Your proxy of choice should be able to help with this. Acquiring and configuring certificates is not covered here. If you use a Cloudflare tunnel then the certificates are all handled by Cloudflare for you with zero ongoing admin overhead.

Proxying the PDS

The PDS can be proxied behind something like Apache, Nginx, Traefik or a Cloudflare tunnel. You will need to proxy port 80 and 443 for all requests to *.example.com/*.

For a Cloudflare tunnel in particular you would need two rules:

Public Hostname Path Service Origin Configurations
pds.example.com / http://localhost:6000 httpHostHeader: pds.example.com
*.example.com /.well-known/ http://localhost:6000 httpHostHeader: *.example.com

The second rule ensures that @user.example.com can be looked up via https (rather than DNS) and will return the did for the user. This means that you don't have to add _atprot.user TXT records to your DNS zone for your domain.

Other proxies configurations are left to the reader to work out 🙂

Container logs

If things don't seem to be working you can look at the container logs with:

docker logs pds -f | jq -r '
(.time / 1000 | strflocaltime("%d %b %y %T") ) + " - " + (.level | tostring) + " - " + 
if .req then
    (.res.statusCode | tostring) + " - " + ( .req.headers["x-forwarded-for"] ) + " " + .req.url
elif .err then
    ( .err["$metadata"].httpStatusCode? | tostring ) + " -" + " [" + .name + "] " + ( .err.message | tostring )
else 
    if .status then 
        (.status | tostring) 
    else
        "   " 
    end
    + " > " + " [" + .name + "] " + .msg + " " +
    if .did then
        .did
    else
        .uri.host
    end  
end'

Copy/paste into your favourite shell to see the logs from the container.

Note: this requires jq to be installed to parse the JSON log format.

# AT Proto Personal Data Server for use with BlueSky
services:
pds:
container_name: pds
# Image is pulled below in build
# image: ghcr.io/bluesky-social/pds:0.4
build:
context: .
# Adds pdsadmin utility into image
dockerfile_inline: |
FROM ghcr.io/bluesky-social/pds:0.4
RUN apk add bash curl openssl jq util-linux-misc
RUN curl --silent --show-error --fail --output '/usr/local/bin/pdsadmin' 'https://raw.githubusercontent.com/bluesky-social/pds/main/pdsadmin.sh'
RUN sed -i 's/--force/-f/g' /usr/local/bin/pdsadmin
RUN chmod +x /usr/local/bin/pdsadmin
restart: unless-stopped
volumes:
# Where to store the pds information
- /opt/pds:/pds
ports:
# Change the first port to something that doesn't conflict with other services.
# port 6000 on the host to port 3000 in the container.
- '6000:3000'
environment:
- LOG_ENABLED=true
- [email protected]
# openssl rand --hex 16
- PDS_ADMIN_PASSWORD=my-secret-password
- PDS_BLOBSTORE_DISK_LOCATION=/pds/blocks
- PDS_BLOBSTORE_DISK_TMP_LOCATION=/pds/temp
- PDS_BLOB_UPLOAD_LIMIT=52428800
- PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app
- PDS_BSKY_APP_VIEW_URL=https://api.bsky.app
- PDS_CRAWLERS=https://bsky.network
- PDS_DATA_DIRECTORY=/pds
- PDS_DID_PLC_URL=https://plc.directory
# If using Google Workspace this email address must exist (either as a user, or as an alias)
- [email protected]
# Generate an app password for this
- PDS_EMAIL_SMTP_URL=smtps://admin%40example.com:[email protected]:465/
# PDS hostname can also be the domain, eg: example.com
- PDS_HOSTNAME=pds.example.com
# openssl rand --hex 16
- PDS_JWT_SECRET=
# openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32
- PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=
- PDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndac
- PDS_REPORT_SERVICE_URL=https://mod.bsky.app
# user handles will be @user.example.com
- PDS_SERVICE_HANDLE_DOMAINS=.example.com
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment