Host Your Own Bluesky PDS: A Complete Azure-Powered Guide
How I built and configured a Bluesky PDS in Azure
Ever wanted to run your own slice of the Fediverse? Bluesky makes it possible with their open protocol, ATProto, and their Personal Data Server (PDS).
This post walks through how I set up a fully self-hosted, domain-backed, TLS-secure Bluesky PDS on Azure, complete with:
- Custom root-domain handle
- Working email communication via Azure Communication Services
- Automated compressed backups
Why Self-Host a PDS?
Because I can. But also...
- Full control over identity (I use @tophhie.cloud as my handle).
- Zero reliance on third-party PDS providers
- Transparent data storage and backup
⚙️ The Setup Overview
- Virtual Machine: Ubuntu 22.04 VM (Standard_B1s)
- Domain: pds.tophhie.cloud (DNS managed via Cloudflare)
- Bluesky PDS: github.com/bluesky-social/pds
- Email: Azure Communication Services SMTP Relay
- Backups: Scheduled compressed tarballs to Azure File Share
🧱 1. Provision the VM
A simple Ubuntu VM with a static public IP. Make sure port 443 and 80 are open.
🔧 2. Deploying the PDS
Install the PDS
Install the PDS with Bluesky's ready built script
curl https://raw.githubusercontent.com/bluesky-social/pds/main/installer.sh | sudo bash
Follow the on-screen set up instructions, including:
- Specifying your PDS hostname (mine is pds.tophhie.cloud)
- Creating the required DNS records
- Optionally, creating your first user (I migrated my user, so skipped this step)
Set up the email communication
Edit the pds.env
file (usually located at /pds/pds.env
) and add the email configuration:
PDS_EMAIL_FROM_ADDRESS="Tophhie Cloud PDS <donotreply@pds.tophhie.cloud>"
PDS_EMAIL_SMTP_URL=smtp://pds-donotreply:super-secret-pass@smtp.azurecomm.net:587
💾 3. Backups
I mount an Azure File Share and run this cron-d job every night:
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
SRC_DIR="/pds"
DEST_DIR="/mnt/pds-backups"
ARCHIVE_NAME="pds-backup-$TIMESTAMP.tar.gz"
ARCHIVE_PATH="$DEST_DIR/$ARCHIVE_NAME"
LOG_FILE="/var/log/pds-backup.log"
# Run tar
sudo tar -czf "$ARCHIVE_PATH" -C "$SRC_DIR" . 2>&1 | sudo tee -a "$LOG_FILE"
# Log success
echo "[+] Backup created at $ARCHIVE_PATH on $(date)" | sudo tee -a "$LOG_FILE" > /dev/null
🏃♀️➡️ 4. Migration from Bluesky's PDS
I installed the Indigo goat tool in preparation for migrating my Bluesky account across from Bluesky's own PDS to my own.
Logged in...
goat account login -u $OLDHANDLE -p $OLDPASSWORD
I was then sent a code (because I have two-factor, as should you... for everything). And logged in again...
goat account login -u $OLDHANDLE -p $OLDPASSWORD --auth-factor-token XXXXX-XXXXX
Then requested a PLC identity token... which was emailed to me!
goat account plc request-token
Created an invite code on my own PDS... which I took a note of.
sudo pdsadmin create-invite-code
Then kicked off the migration...
goat account migrate \
--pds-host https://pds.tophhie.cloud \
--new-handle chris.pds.tophhie.cloud \
--new-password MY_PASSWORD \
--new-email MY_EMAIL_ADDRESS \
--plc-token PLC_TOKEN_FROM_EMAIL \
--invite-code INVITE_CODE_FROM_PDS
All my data was then migrated across to my own PDS; posts, likes, comments, following, followers, everything.
🌐 5. Reconfiguring my Handle
Once everything was migrated across, I logged into the Bluesky web app using my own PDS. Using the --new-handle
I'd provided in the previous step, and my password.
I had to specify a temporary new handle, which had to be a subdomain of my PDS host (chris.pds.tophhie.cloud).
Once logged in, I verified my email address... which was sent via Azure Communication Services configured in step 2.
Went across to my account settings and updated my handle to tophhie.cloud
. As I'd already created a DNS TXT record when I updated the handle for Bluesky, I didn't need to do this again.
_atproto.tophhie.cloud → "did:plc:ggobmtqnjirtchpwgydxoecb"
The handle was immediately verified, and updated! Visible on the PDS's terminal.
_@_:~$ sudo pdsadmin account list
Handle Email DID
tophhie.cloud chris.greenacre@tophhie.co.uk did:plc:ggobmtqnjirtchpwgydxoecb
🏁 Done!
The PDS is online, secure, verified, and backed up. Feels good to own my corner of the Fediverse.
Got questions or want to roll your own? Hit me up 👋