How to Migrate a Mastodon Instance From Bare Metal to Docker
🔍 WiseChecker

How to Migrate a Mastodon Instance From Bare Metal to Docker

Running a Mastodon instance on bare metal gives you complete control but often leads to dependency conflicts and manual update procedures. Moving to Docker containerization standardizes the environment, simplifies upgrades, and reduces the risk of configuration drift. This guide walks through the exact steps to export your existing Mastodon data, set up a Docker-based instance, and import your database and files without losing any posts or user accounts.

Key Takeaways: Migrating Mastodon From Bare Metal to Docker

  • pg_dump and pg_restore: Export and import the PostgreSQL database while preserving all accounts, posts, and relationships.
  • rsync of system directory: Copy uploaded media files and custom emoji from the old server to the new Docker volume.
  • docker-compose.yml configuration: Mirror the original environment variables for secrets, database credentials, and domain name.
  • Running db:migrate after import: Apply any pending schema changes so the Docker instance matches the current database structure.

ADVERTISEMENT

Understanding the Migration Process From Bare Metal to Docker

Mastodon stores its data in two main locations: a PostgreSQL database and a file system directory for uploaded media. The database contains everything from user accounts and posts to follower relationships and reports. The file system holds user avatars, headers, custom emoji, and media attachments. Migrating to Docker means you must transfer both components while keeping the same domain name and secret keys.

The bare metal installation typically uses a system package manager like apt or yum, with Mastodon running directly on the server. A Docker installation uses containers defined in a docker-compose.yml file. The core Mastodon application, Sidekiq background workers, and streaming API each run in separate containers. The migration does not change the underlying data format, so a direct export and import works.

Before starting, confirm that your new Docker host meets the minimum requirements: at least 2 CPU cores, 4 GB of RAM, and enough disk space to hold your media files. You also need Docker Engine and Docker Compose installed on the target machine. If you use a reverse proxy like Nginx or Caddy on the bare metal server, plan to reconfigure it for the Docker setup or run the proxy inside a separate container.

Steps to Migrate Mastodon From Bare Metal to Docker

  1. Stop Mastodon services on the bare metal server
    Run systemctl stop mastodon- to stop the web, sidekiq, and streaming services. This prevents new data from being written during the export. Verify all processes are stopped with systemctl status mastodon-.
  2. Export the PostgreSQL database
    Use pg_dump -Fc mastodon_production > mastodon_production.dump as the Mastodon database user. The custom format (-Fc) compresses the dump and allows parallel restore later. Transfer the dump file to the Docker host using scp or rsync.
  3. Copy the media and system files
    On the bare metal server, locate the Mastodon system directory (usually /home/mastodon/live/public/system). Run rsync -avz /home/mastodon/live/public/system/ user@new-server:/path/to/docker-volume/system/. Include the .env.production file from the bare metal server for secret keys and environment variables.
  4. Set up the Docker environment
    On the new server, create a directory for Mastodon and place the official docker-compose.yml from the Mastodon repository. Copy your .env.production file into this directory. Edit docker-compose.yml to map the media volume to the path where you placed the rsynced files. For example, add ./system:/mastodon/public/system under the web and sidekiq services.
  5. Start the database container only
    Run docker compose up -d db to start only the PostgreSQL container. Wait 10 seconds for the database to initialize. Then restore the dump using docker compose exec -T db pg_restore -U postgres -d mastodon_production < mastodon_production.dump. The -T flag suppresses progress output and speeds up the operation.
  6. Run database migrations
    After the restore completes, start all containers with docker compose up -d. Run docker compose exec web bundle exec rails db:migrate to apply any schema changes that the Docker version expects. This step ensures the database structure matches the current Mastodon code.
  7. Regenerate the asset pipeline and cache
    Run docker compose exec web bundle exec rails assets:precompile to compile CSS and JavaScript. Then run docker compose exec web bundle exec rails tmp:cache:clear to clear any cached data that references the old file paths.
  8. Update DNS and reverse proxy
    Point your domain name to the new server IP address. Configure your reverse proxy to forward traffic to the Mastodon web container (port 3000 by default). If you use Nginx, the official Mastodon documentation provides a sample configuration. Wait for DNS propagation (usually 5 to 30 minutes).
  9. Verify the migration
    Open your Mastodon instance in a browser. Log in with an existing account and check that your profile picture, posts, and followers appear correctly. Post a new toot and confirm it appears on the public timeline. Monitor the Docker logs with docker compose logs -f for any errors.

ADVERTISEMENT

Common Issues After Migrating Mastodon to Docker

Database restore fails with role does not exist

The pg_restore command may fail if the PostgreSQL container uses a different database user than the bare metal server. Create the correct role manually before restoring. Connect to the database container with docker compose exec db psql -U postgres and run CREATE ROLE mastodon WITH LOGIN SUPERUSER;. Then retry the restore.

Media files appear broken or missing

If avatars or attachments show as broken images, the volume path in docker-compose.yml likely does not match the rsync target. Verify that the system directory is mounted at /mastodon/public/system inside the web and sidekiq containers. Run docker compose exec web ls /mastodon/public/system to confirm the files are visible.

Sidekiq workers queue up and never process

When Sidekiq cannot connect to Redis or the database, jobs pile up. Check that the Redis container is running with docker compose ps. Verify the REDIS_URL and DB_HOST environment variables in your .env.production file point to the Docker service names (e.g., redis and db) rather than IP addresses or localhost.

Login fails with invalid secret key

The SECRET_KEY_BASE, OTP_SECRET, and VAPID_PRIVATE_KEY must match the original bare metal values. Copy the entire .env.production file from the old server. If any key is missing, generate new ones with docker compose exec web bundle exec rake secret, but doing so invalidates all existing user sessions.

Item Bare Metal Docker
Dependency management Manual package installation via apt or yum Automatic container images with fixed versions
Database backup method pg_dump and manual cron script docker compose exec db pg_dump or automated volume snapshots
Update procedure Stop services, pull git, bundle install, run migrations docker compose pull && docker compose up -d
File system location /home/mastodon/live/public/system Docker volume mounted to /mastodon/public/system
Configuration file .env.production in the Mastodon user home .env.production in the project directory, read by containers

After completing the migration, your Mastodon instance runs entirely in Docker containers. Updates now require only pulling new images and restarting services. Schedule regular database backups using docker compose exec db pg_dump -U postgres mastodon_production and store the dump off-server. For added safety, test the migration on a staging server first to catch any environment-specific issues before touching the production instance.

ADVERTISEMENT