
MOOving to a self-hosted Bluesky PDS
MOOving to a self-hosted Bluesky PDS êŽë š
Bluesky (dbushell.com) is a âTwitter cloneâ that runs on the AT Protocol. I have to be honest, Iâd struggle to explain how atproto works. I think itâs similar to Nostr but like, good? When atproto devs talk about The Atmosphere they sound like blockchain bros. The marketing needs consideration. Bluesky however, is a lot of fun. Feels like early Twitter.
Nobody cool uses Twitter anymore ever. Itâs a cesspit of racists asking Gork to undress women.
Self-hosting
Mastodon and Bluesky (dbushell.com) are the social platforms I use. Iâve always been tempted to self-host my own Mastodon instance but the requirements are steep. I use the omg.lol server instead. Self-hosting the Bluesky PDS (bluesky-social/pds) is much less demanding.
My setup includes:
Raspberry Pi 5
This is the host machine I glued an NVMe onto the underside. All services run as Docker containers for easy security sandboxing. I say easy but it took many painful years to master Docker. I have the Pi on a VLAN firewall because Iâm extra paranoid.
Bluesky PDS
I setup my Bluesky PDS (bluesky-social/pds) using the official Docker container. Itâs configure with environment variables (bluesky-social/pds#environment-variables) and has a single data volume mounted. I backup that volume to my NAS.
Caddy
Iâve put Caddy in front of the PDS container. Right now it just acts as a reverse proxy. This gives me flexibility later if I want to add access logs, rate limiting, or other plugins.
Cloudflare Tunnel
Booo! If you know a good European alternative please let me know! The tunnel links Caddy to the outside world via Cloudflare to avoid exposing my home IP address. Cloudflare also adds an extra level of bot protection.
The guides I followed suggest adding wildcard DNS for the tunnel. Cloudflare has shuffled the dashboard for the umpteenth time and I canât figure out how. I think sub-domains are only used for user handles, e.g. user.example.net. I use a different custom domain for my handle (@dbushell.com) with a manual TXT record to verify.
Proton SMTP
Allowing the PDS to send emails isnât strictly necessary. Itâs useful for password resets and I think itâll send a code if I migrate PDS again. I went through the hassle of adding my PDS domain to Proton Mail and followed their SMTP guide.
PDS_EMAIL_SMTP_URL=smtp://pds@example.net:S3CR3TT0K3N@smtp.protonmail.ch:587
PDS_EMAIL_FROM_ADDRESS=pds@example.net
This shows how the PDS enviornment variables are formatted. It took me forever to figure out where the username and password went.
PDS MOOver
PDS MOOver by Bailey Townsend (baileytownsend.dev) is the tool that does the data migration. It takes your Bluesky password and probably sees your private key, so use at your own risk! I setup a new account to test it before I YOLOâd my main.
MOOve successful!
I still login at bsky.app but I now select âcustom account providerâ and enter my PDS domain. SkyTools has a tool that confirms it. Bluesky Debug can check handles are verified correctly. PDSIs.dev is a neat atproto explorer.
I cross-referenced the following guides for help:


Most of the Cloudflare stuff is outdated because Cloudflare rolls dice every month.
Bluesky is still heavily centralised but the atproto layer allows anyone to control their own data. I like doing that on principle. I donât like maintenance, but Iâve heard thatâs minimal for a PDS. Supposedly itâs possible to migrate back to Blueskyâs PDS if I get bored.
Iâm tempted to build something in The Atmosphere. Any ideas?
Update for 3rd March 2026
Xan suggested I add a favicon which can appear on witchsky.app. In Docker I mounted a âpublicâ directory to the Caddy container. In the Caddyfile route I added a handle to match /favicon.ico and serve the file (before the reverse proxy to the PDS container). I knew Caddy would come in handy!