How to set up Mastodon using Docker Compose

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 #

  1. Replace placeholders: Update your-domain.com with your actual domain
  2. Email configuration: Set up proper SMTP settings for email notifications
  3. Backup regularly: Implement a backup strategy for your database
  4. Security: Use SSL/TLS certificates and keep your system updated
  5. 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.