Bluesky PDS Migration With Docker Compose: Walkthrough
🔍 WiseChecker

Bluesky PDS Migration With Docker Compose: Walkthrough

Running your own Bluesky PDS gives you full control over your account data and moderation. Migrating that PDS to a new server can feel risky because you must move the database, storage, and configuration files without losing data or breaking federation. This article walks you through a complete PDS migration using Docker Compose, from backing up the old server to verifying the new instance is live. You will need SSH access to both servers and a basic understanding of Docker commands.

Key Takeaways: PDS Migration Steps With Docker Compose

  • Back up the PDS stack: Stop containers and copy the pds-data directory, including the SQLite database and storage blobs.
  • Restore on the new server: Copy the backup archive, place it in the same relative path, and restart the containers.
  • Update DNS records: Change the A and AAAA records for your PDS domain to point to the new server IP address.

What a PDS Migration Involves

A Bluesky PDS stores three critical components: the SQLite database containing all account data, the storage directory containing uploaded images and media, and the environment variables in the .env file. Docker Compose bundles these components into a portable stack. When you migrate, you move the entire pds-data directory and the .env file to the new machine. The PDS software itself is pulled from the same container image, so no code changes are needed. The only external change is updating the DNS records so that the Bluesky network can find your PDS at the new IP address.

The migration process assumes both the old and new servers run the same operating system and Docker version. If the new server uses a different architecture, such as moving from x86_64 to ARM64, verify that the Bluesky PDS container image supports it. As of this writing, the official image supports both architectures.

Prerequisites

Before starting, confirm you have the following:

  • SSH access to the old PDS server and the new PDS server
  • Docker and Docker Compose installed on both machines
  • Root or sudo privileges on both machines
  • A DNS provider where you can change A and AAAA records for your PDS domain
  • Enough disk space on the new server to hold the pds-data directory

Steps to Migrate the Bluesky PDS to a New Server

The migration follows three phases: backup on the old server, transfer and restore on the new server, and DNS update. Perform these steps in order to avoid data loss.

  1. Stop the PDS containers on the old server
    SSH into the old server and navigate to the directory containing your docker-compose.yml file. Run sudo docker compose down to stop all containers. This prevents any writes to the database while you create the backup.
  2. Create a compressed archive of the PDS data directory
    Run sudo tar -czf pds-backup.tar.gz pds-data/ in the same directory as the docker-compose.yml file. The pds-data directory contains the SQLite database and the storage blobs. If your .env file is not inside pds-data, include it separately: sudo tar -czf pds-backup.tar.gz pds-data/ .env.
  3. Copy the archive to the new server
    Use scp or rsync to transfer the archive. For example: scp pds-backup.tar.gz user@new-server-ip:/home/user/. Ensure the destination directory exists and has enough free space.
  4. Restart the old PDS containers
    On the old server, run sudo docker compose up -d to bring the PDS back online. Users will continue to access the old server until the DNS change propagates.
  5. Prepare the new server directory structure
    SSH into the new server. Create the directory where the PDS will run: mkdir -p /opt/bluesky-pds. Copy the docker-compose.yml file from the old server into this directory. You can transfer it with scp as well.
  6. Extract the backup archive on the new server
    Move the archive into the PDS directory: sudo mv pds-backup.tar.gz /opt/bluesky-pds/. Then extract it: sudo tar -xzf pds-backup.tar.gz. Verify that the pds-data directory and .env file are present.
  7. Start the PDS containers on the new server
    Run sudo docker compose up -d. Check the logs with sudo docker compose logs -f to confirm the PDS starts without errors. Look for a line indicating that the server is listening on port 2583.
  8. Update the DNS records for your PDS domain
    Log in to your DNS provider and change the A record for your PDS domain to the new server IP address. If your PDS uses IPv6, also update the AAAA record. The TTL value determines how quickly the change propagates. Set a low TTL of 300 seconds before the migration to speed up the switch.
  9. Verify the new PDS is reachable
    Wait for DNS propagation, then run curl https://your-pds-domain.com/xrpc/_health from any machine. A healthy response returns a JSON object with "version": "...". You can also open the URL in a browser to confirm.

If the Migration Has Issues After Restart

Several problems can appear after you move the PDS. The steps below address the most common ones.

The PDS container fails to start with a permission error

The pds-data directory and files may have wrong ownership on the new server. Run sudo chown -R 1000:1000 pds-data/ inside the PDS directory. The PDS container runs as user ID 1000 by default. If the .env file sets a different UID, use that value instead.

Existing accounts cannot log in after migration

This usually means the database did not copy correctly. Check that the pds-backup.tar.gz file size matches the original pds-data directory size. Re-run the backup step and verify the archive integrity with tar -tzf pds-backup.tar.gz to list the contents.

The health endpoint returns 503 Service Unavailable

The PDS cannot connect to the Bluesky relay or the PLC directory. Confirm that the .env file contains the correct PDS_HOST and PLC_ROTATION_KEY values. Also verify that the new server can make outbound HTTPS requests to the Bluesky network.

Old Server vs New Server: Key Differences After Migration

Item Old Server New Server
IP address Original IP New IP assigned to the server
DNS records Pointing to old IP Updated to new IP
PDS version Version before migration Same version if image tag is pinned; otherwise latest
Data Original database and blobs Copy of the data from the backup archive

You now have a fully migrated Bluesky PDS running on the new server. Test your account by posting a new message and verifying it appears on the public timeline. As a next step, consider enabling automated daily backups of the pds-data directory to a remote location using a cron job and rsync. This protects against hardware failure on the new server.