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.
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
- Stop Mastodon services on the bare metal server
Runsystemctl 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 withsystemctl status mastodon-. - Export the PostgreSQL database
Usepg_dump -Fc mastodon_production > mastodon_production.dumpas 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. - Copy the media and system files
On the bare metal server, locate the Mastodon system directory (usually/home/mastodon/live/public/system). Runrsync -avz /home/mastodon/live/public/system/ user@new-server:/path/to/docker-volume/system/. Include the.env.productionfile from the bare metal server for secret keys and environment variables. - Set up the Docker environment
On the new server, create a directory for Mastodon and place the officialdocker-compose.ymlfrom the Mastodon repository. Copy your.env.productionfile into this directory. Editdocker-compose.ymlto map the media volume to the path where you placed the rsynced files. For example, add./system:/mastodon/public/systemunder the web and sidekiq services. - Start the database container only
Rundocker compose up -d dbto start only the PostgreSQL container. Wait 10 seconds for the database to initialize. Then restore the dump usingdocker compose exec -T db pg_restore -U postgres -d mastodon_production < mastodon_production.dump. The-Tflag suppresses progress output and speeds up the operation. - Run database migrations
After the restore completes, start all containers withdocker compose up -d. Rundocker compose exec web bundle exec rails db:migrateto apply any schema changes that the Docker version expects. This step ensures the database structure matches the current Mastodon code. - Regenerate the asset pipeline and cache
Rundocker compose exec web bundle exec rails assets:precompileto compile CSS and JavaScript. Then rundocker compose exec web bundle exec rails tmp:cache:clearto clear any cached data that references the old file paths. - 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). - 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 withdocker compose logs -ffor any errors.
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.