Host Your Own Bluesky PDS: A Complete Azure-Powered Guide

How I built and configured a Bluesky PDS in Azure

Host Your Own Bluesky PDS: A Complete Azure-Powered Guide
Photo by Kumiko SHIMIZU / Unsplash

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 👋