How to set up Mastodon using Docker Compose
Prerequisites #
- Docker and Docker Compose installed
 - Domain name pointing to your server
 
1. Create Project Directory #
mkdir mastodon
cd mastodon
2. Create Docker Compose File #
Create a docker-compose.yml file:
version: '3'
services:
  db:
    restart: always
    image: postgres:14-alpine
    shm_size: 256mb
    networks:
      - internal_network
    healthcheck:
      test: ['CMD', 'pg_isready', '-U', 'postgres']
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_HOST_AUTH_METHOD=trust
  redis:
    restart: always
    image: redis:7-alpine
    networks:
      - internal_network
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
    volumes:
      - redis_data:/data
  web:
    restart: always
    image: tootsuite/mastodon:latest
    networks:
      - external_network
      - internal_network
    healthcheck:
      test: ['CMD-SHELL', 'wget -q --spider http://localhost:3000/health || exit 1']
      timeout: 10s
    depends_on:
      - db
      - redis
    environment:
      - DB_HOST=db
      - DB_USER=postgres
      - DB_NAME=postgres
      - DB_PASS=
      - REDIS_HOST=redis
      - LOCAL_DOMAIN=your-domain.com
      - SINGLE_USER_MODE=false
      - SMTP_SERVER=smtp.mailgun.org
      - SMTP_PORT=587
      - SMTP_LOGIN=your-smtp-login
      - SMTP_PASSWORD=your-smtp-password
      - SMTP_FROM_ADDRESS=notifications@your-domain.com
    volumes:
      - ./public/system:/mastodon/public/system
    ports:
      - "3000:3000"
    command: bash -c "rm -f /mastodon/tmp/pids/server.pid && bundle exec rails s -p 3000"
  streaming:
    restart: always
    image: tootsuite/mastodon:latest
    networks:
      - external_network
      - internal_network
    depends_on:
      - db
      - redis
    environment:
      - DB_HOST=db
      - DB_USER=postgres
      - DB_NAME=postgres
      - DB_PASS=
      - REDIS_HOST=redis
      - LOCAL_DOMAIN=your-domain.com
    volumes:
      - ./public/system:/mastodon/public/system
    ports:
      - "4000:4000"
    command: node ./streaming
  sidekiq:
    restart: always
    image: tootsuite/mastodon:latest
    networks:
      - internal_network
    depends_on:
      - db
      - redis
    environment:
      - DB_HOST=db
      - DB_USER=postgres
      - DB_NAME=postgres
      - DB_PASS=
      - REDIS_HOST=redis
      - LOCAL_DOMAIN=your-domain.com
    volumes:
      - ./public/system:/mastodon/public/system
    command: bundle exec sidekiq
networks:
  external_network:
  internal_network:
    internal: true
volumes:
  postgres_data:
  redis_data:
3. Create Environment File #
Create a .env.production file with your configuration:
# Database
DB_HOST=db
DB_PORT=5432
DB_NAME=postgres
DB_USER=postgres
DB_PASS=
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=
# Mastodon
LOCAL_DOMAIN=your-domain.com
SECRET_KEY_BASE=generate-a-secret-key
OTP_SECRET=generate-an-otp-secret
# Web Push
VAPID_PRIVATE_KEY=generate-vapid-private-key
VAPID_PUBLIC_KEY=generate-vapid-public-key
# SMTP (Email)
SMTP_SERVER=smtp.mailgun.org
SMTP_PORT=587
SMTP_LOGIN=your-email-login
SMTP_PASSWORD=your-email-password
SMTP_AUTH_METHOD=plain
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_FROM_ADDRESS=notifications@your-domain.com
# Optional: S3 storage
S3_ENABLED=false
# S3_BUCKET=your-bucket-name
# AWS_ACCESS_KEY_ID=your-access-key
# AWS_SECRET_ACCESS_KEY=your-secret-key
# S3_REGION=us-east-1
# S3_PROTOCOL=https
# S3_HOSTNAME=s3.amazonaws.com
4. Generate Secrets #
Run the following commands to generate the required secrets:
# Generate secret key base
docker run --rm tootsuite/mastodon:latest bundle exec rake secret
# Generate OTP secret
docker run --rm tootsuite/mastodon:latest bundle exec rake secret
# Generate VAPID keys
docker run --rm tootsuite/mastodon:latest bundle exec rake mastodon:webpush:generate_vapid_key
Update your .env.production file with these generated values.
5. Start Mastodon #
# Pull images
docker-compose pull
# Start services
docker-compose up -d
# Run database setup
docker-compose run --rm web bundle exec rake db:migrate
# Pre-compile assets
docker-compose run --rm web bundle exec rake assets:precompile
6. Create Admin User #
docker-compose run --rm web bundle exec rake mastodon:setup
Follow the interactive prompts to create your admin account.
7. Reverse Proxy Setup (Nginx) #
Create an Nginx configuration file:
map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}
server {
  listen 80;
  listen [::]:80;
  server_name your-domain.com;
  
  # Uncomment for SSL
  # listen 443 ssl http2;
  # listen [::]:443 ssl http2;
  # ssl_certificate /path/to/certificate.crt;
  # ssl_certificate_key /path/to/private.key;
  
  root /home/mastodon/live/public;
  
  location / {
    try_files $uri @proxy;
  }
  
  location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {
    add_header Cache-Control "public, max-age=31536000, immutable";
    try_files $uri @proxy;
  }
  
  location /sw.js {
    add_header Cache-Control "public, max-age=0";
    try_files $uri @proxy;
  }
  
  location @proxy {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Proxy "";
    proxy_pass_header Server;
    
    proxy_pass http://127.0.0.1:3000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    
    proxy_connect_timeout       90;
    proxy_send_timeout          90;
    proxy_read_timeout          90;
    
    add_header Strict-Transport-Security "max-age=31536000";
  }
  
  location /api/v1/streaming {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Proxy "";
    
    proxy_pass http://127.0.0.1:4000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
  }
  
  error_page 500 501 502 503 504 /500.html;
}
8. Useful Commands #
# Check logs
docker-compose logs -f
docker-compose logs -f web
docker-compose logs -f sidekiq
# Stop services
docker-compose down
# Backup database
docker-compose exec db pg_dump -U postgres postgres > backup.sql
# Update Mastodon
docker-compose pull
docker-compose run --rm web bundle exec rake db:migrate
docker-compose run --rm web bundle exec rake assets:precompile
docker-compose restart
Important Notes #
- Replace placeholders: Update 
your-domain.comwith your actual domain - Email configuration: Set up proper SMTP settings for email notifications
 - Backup regularly: Implement a backup strategy for your database
 - Security: Use SSL/TLS certificates and keep your system updated
 - Resources: Mastodon can be resource-intensive; ensure your server has adequate RAM and CPU
 
This setup provides a basic Mastodon instance. You may want to customize it further based on your needs, such as adding object storage for media files or configuring additional security measures.