So, I now self host my PDS1

Why?

Good question.

Every few years to a few months since I was like 152, I've done something with computers that I usually shouldn't do3

Sky as blue as EU4

I started my ATProto journey on the mothership of the PDS like most folks in the space, before migrating earlier this year to like most prominent EU folks did this year. While Bluesky has been a pretty good host, it's still a US entity. It can operate servers in Europe to store data but you still have to trust who-knows-what treaties or court cases would govern EU/US data transfers5. But Eurosky is a EU entity with EU servers, so you can host your social filesystem there there and no one in the US can mess with6.

For that migration I used the Eurosky EU-HAUL service and it was pretty painless. and using Eurosky I saw no day-to-day differences in using Bluesky, Leaflet, npmx.dev, Tangled et al, between the Bluesky PDS and Eurosky. So happy out. But there was one problem.

Auth pains

On the Bluesky PDS, in order to login on a new device on a new app the flow goes like this:

  1. 1.

    Username (Atmosphere account handle)

  2. 2.

    Password (password)

  3. 3.

    A 2FA code

And this is where the frustration is: there is exactly one way to get a 2FA code for Bluesky and it's email.

This is not the most flexible auth scheme. You can't set up either a TOTP authenticator or passkeys with your account. It's kinda annoying to reach for and wait for an email, especially since most password managers can auto fill both TOTP and passkeys with a press of a button7.

This issue is shared by both the Eurosky and Bluesky PDS's, I eventually got tired of waiting for Eurosky to implement passkeys and decided to go full self hosting.

The setup

I set up a cheap Hetzner box, initially with Debian but I've decided to use the oppertunity to learn NixOS8, so had nixos-anywhere install over the intial image. A flake was build that depended on the tranquil flake, added to the Tailscale tailnet, Caddy as the remote proxy, email smtp was handled by a free Resend account, local storage for blobs and the Postgres data volume, and all the domains setup with the Approprate dns records. This is all relatively straight forward, this PDS should not see a lot of traffic since I'll be the only user. A Hetzner bucket is being used to backup the blobs and database via a cron job; I'm gonna look at making sure this is robust and probably copy to my local NAS as well, so I can do a full recovery if something goes wrong.

My PDS ends up live at pds.dogpawhat.tech at it was time for the migration. there's a few PDS migration tools here:

Since I had used EU-HAUL before I choose that. I log out of Bluesky and everything else on the Eurosky account, trigger the migration9, copy the back up and rotation key, and at the end the old account is deactivated and the new one is activated.

Last bit is where things went odd.

My kingdom for an account activation

Logging back into Bluesky, my heart sinks when I realise that instead of doing an OAuth redirect to the new PDS where I could use the passkeys I set up, it triggers the old email 2FA flow. Turns out the Bluesky app hasn't set up the newer OAuth flows that apps like Leaflet or Witchsky has.

Bummer. This is probably why Eurosky hadn't migrated.

Well. Gonna have to live with it now. Hopefully nothing else breaks.

...Ah crap.

When I login to Bluesky, I can look a the network just fine, but it gives me a invalid JWT warning for when I look at my own profile. A quick look at the network tab reveals a lot of 401 errors to the new pds, so something is very off.

Great.

I start doing the debugging process like so:

  • Can I login to other atproto apps? Yeah logging in into leafet works.

  • What non-Bluesky way is there to inspect my account. https://pdsls.dev/ seems to confirm my account lives on the new pds. I found https://debug.hose.cam/ to inspect my account as well; It looked like things should work except the Bluesky relay looked out of date (marked as "behind")

A comment on the Tranquil tangled suggested deactivating the account which made me think "hey did Eurosky deactivate the old account". Logging back into Eurosky it looked like the old account was still active. Press "deactivate" and see if it fixes it?

Well now my profile says "account deactivated" when I look at it. Crap.

I realised that Blacksky had it's own relay and app view that would show my posts, so I logged into there and sure enough I could see my posts. It showed a test post from the Blacksky app, from the Bluesky app (were I could post and not see my own post!) and I tested creating an app.bsky.feed.post record directly in Tranquil's Repository Explorer. All shows up in Blacksky10.

So I now know that the rest of the ATProto nextwork save for BlueSky (which is like 80% of the network at least) knows this migration happened. and it has recored the manual deactivation on Eurosky but not the new activation.

I've nearly resigned myself to having to send a support email to BlueSky, but I'm still in that mindset of "There must be some button to press that makes this go away". I recall reading that the deactivation of the old PDS must be followed by activating the new PDS. Could I trigger a new activation event?

I couldn't find a way to reactivate the account via Tranquil, so I fell back to goat:

goat account activate

...

...

Load the profile on Bluesky...

IT LIVES!!!

My profile shows up, the PDS debugger shows the rely has updated...

I'm done. I did it.

Frodo Baggins, The Lord of the Rings: The Return of the King, after the One Ring is destroyed: "It's done"

Conclusion

So yeah, my PDS is working now and I'm self hosting it for... not a whole lot of gain.

But come on. It's cool as hell anyway. The PDS setup (along with the bring your own domain feature) is why ATProto in general is so much fun for devs to build on and hopefully build a more functionailty social landscape. If I had more of homelab I'd have done this a while ago.

It it kinda annoying that the Bluesky app doesn't support newer OAuth for the passkeys or that the relay didn't process the migration properly. That said it does not seem like EU-HAUL properly deactivated the Eurosky PDS like it was meant to so that part ended up having to be done by myself. Basically, I can't recommend EU-HAUL if you want to migrate away from Eurosky; I think goat and PDS MOOver are the state of the art for that at the moment. Hopefully these get fixed as we move forward as an ecosystem, but I highly recommend learning how account migration works under the hood before undertaking it.

Thanks have to be given to the folks maintaining the tools that helped me thought this process:

  • (goat cli)

  • (the PDS Debugger)

And I will say best of luck to , I'm sorry I should have read the fine print on the auth systems.

I'll keep the box running for a bit anyway. hopefully I'm lucky and this is the worst I see.