[homepage|forum|cv] WM-106 [text|html] [remarks]
              
Document: WM-106                                                 P. Webb
Category: Socail                                              2026-10-26

                   Self-hosting Mastodon and Bluesky

Abstract

   Remember re/thinking Twitter handles for your various projects? It’s
   2026, I’m not doing all that for a shit platform. I will spend hours
   wrangling social I control though.

Body

   A few weeks ago[1] I decided to look into self-hosting a Mastodon
   server for my various projects and Sang[2] told me about
   GoToSocial[3], the software he uses to self-host his own. For Bluesky
   I used the official PDS software[4].

   ## GoToSocial

      I decided to put GoToSocial on the same server I’m hosting ~15
      other sites because it’s beefy enough.

      This is how you create accounts:
      

      sudo -u gotosocial ./gotosocial --config-path ./config.yaml admin account create --username friend --email friend@example.org --password 'p@$$w0rd!with`odd*chars'

After the FIRST account you make (this is your admin, right?), you’ll have to promote it to admin:

      sudo -u gotosocial ./gotosocial --config-path ./config.yaml admin account promote --username you

I installed GoToSocial at pr.inc.sh. For some reason, the directory isn’t showing all the accounts I created. Here are the direct links to the accounts I made thus far: — https://pr.inc.sh/@inc — https://pr.inc.sh/@dap — https://pr.inc.sh/@disc — https://pr.inc.sh/@ende — https://pr.inc.sh/@eol ## Bluesky Setting up a PDS on an existing server meant I had to make several adjustments to their guide. I’m already using Caddy so my /pds/compose.yaml didn’t need that.

      services:
        pds:
          container_name: pds
          env_file:
            - /pds/pds.env
          image: ghcr.io/bluesky-social/pds:0.4
          ports:
            - "127.0.0.1:3000:3000"
          restart: unless-stopped
          volumes:
            - type: bind
              source: /pds
              target: /pds
        watchtower:
          command: pds
          container_name: watchtower
          environment:
            WATCHTOWER_CLEANUP: "true"
            WATCHTOWER_SCHEDULE: "0 0 4 * * *"
          image: ghcr.io/nicholas-fedor/watchtower:latest
          restart: unless-stopped
          volumes:
            - type: bind
              source: /var/run/docker.sock
              target: /var/run/docker.sock

(I changed my ports because 3000 is such a common port, I didn’t want interference with something else on my server.) This is how you create accounts:

      docker exec pds goat pds admin account create --email friend+handle@example.org --handle handle.pds.domain --pds-host https://pds.domain --password 'p@$$w0rd!with`odd*chars'

When you run this, you’ll see a DID of the created account. The cool thing about Bluesky is being able to use your domain as your handle. Add a TXT record to your domain with:

      did=did:plc:<output-of-above-command>

and your account will be ready to switch to the domain handle. My PDS is at at.inc.sh. Here’s the Bluesky variants of my Mastodon accounts: — https://bsky.app/profile/inc.sh — https://bsky.app/profile/dap.sh — https://bsky.app/profile/disc.sh — https://bsky.app/profile/ende.sh — https://bsky.app/profile/eol.sh I wasn’t able to get email verification working but the way to get around that is to install sqlite3 on your server.

      apt install -y sqlite3

List the *.sqlite files your PDS generates:

      ls /pds/*.sqlite

You should see:

      /pds/account.sqlite  /pds/did_cache.sqlite  /pds/sequencer.sqlite

Finally, initiate email verification in the Bluesky app and run this in your terminal:

      sudo sqlite3 /pds/account.sqlite "SELECT did, purpose, token FROM email_token;"

You’ll see something like:

      did:plc:abcdefghijklmnopqrstuvwx|confirm_email|ABCDE-FGHIJ

That last bit (ABCDE-FGHIJ) is the code Bluesky is looking for. In the UI, click the button that asks for a code and paste it in. This is your own PDS so if anything goes wrong, why do you need to be emailed? You’d know if something fell over…probably. If your setup is like mine, do NOT run pdsadmin update. It replaces /pds/compose.yaml with the stock file and sets up its own Caddy situation. I should probably put this stuff in 1Password anyway, just in case. This is great because now I won’t feel like I’m spamming people with all my project updates and musings and ramblings. If you opt-in to follow my various accounts, thanks! You can enjoy the deluge of words at your leisure. There’s still the matter of Discord and uhh, meh? I use it but the idea of creating a server for every project sounds insane. Maybe I could just create the one and have a channel for each project? Meh? 🕸️