Self-Host Mastodon with Docker Compose

Self-Hosting May 12, 2023

Requirements

A small instance to support up to 10 users requires around:
2 CPUs
2GB RAM
50GB Storage

Need a Server?

Hetzner - €20 credit on us (ref) - Free Arm instance for 4 months!
Vultr - $100 credit on us (ref) - Expires after 30 days

Setup

Install docker

Follow the docs for your distro: https://docs.docker.com/engine/install/

Create docker network

sudo docker network create --driver=bridge --subnet=10.10.10.0/24 --gateway=10.10.10.1 mastodonnet

Docker compose:
version: "2.1"
services:
  mastodon:
    image: lscr.io/linuxserver/mastodon:latest
    container_name: mastodon
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/London
      - LOCAL_DOMAIN=<domain>    #All other hostnames are blocked by default
      - REDIS_HOST=10.10.10.3
      - REDIS_PORT=6379
      - DB_HOST=10.10.10.2
      - DB_USER=mastodon
      - DB_NAME=mastodon
      - DB_PASS=<PASSWORD>
      - DB_PORT=5432
      - ES_ENABLED=false
      - SECRET_KEY_BASE=
      - OTP_SECRET=
      - VAPID_PRIVATE_KEY=
      - VAPID_PUBLIC_KEY=
      - SMTP_SERVER=mail.example.com
      - SMTP_PORT=25
      - SMTP_LOGIN=
      - SMTP_PASSWORD=
      - [email protected]
      - S3_ENABLED=false
#      - WEB_DOMAIN=mastodon.example.com #optional
#      - ES_HOST=es #optional
#      - ES_PORT=9200 #optional
#      - ES_USER=elastic #optional
#      - ES_PASS=elastic #optional
#      - S3_BUCKET= #optional
#      - AWS_ACCESS_KEY_ID= #optional
#      - AWS_SECRET_ACCESS_KEY= #optional
#      - S3_ALIAS_HOST= #optional
    volumes:
      - ./config:/config
    networks:
      default:
        ipv4_address: 10.10.10.4
    expose:
      - "80"
      - "443"
    restart: unless-stopped

  db:
    restart: always
    image: postgres:14-alpine
    shm_size: 256mb
    networks:
      default:
        ipv4_address: 10.10.10.2
    environment:
      POSTGRES_USER: mastodon
      POSTGRES_PASSWORD: <PASSWORD>
      POSTGRES_DB: mastodon
      POSTGRES_HOST_AUTH_METHOD: trust
    healthcheck:
      test: ['CMD', 'pg_isready', '-U', 'postgres']
    volumes:
      - ./postgres14:/var/lib/postgresql/data

  redis:
    restart: always
    image: redis:7-alpine
    networks:
      default:
        ipv4_address: 10.10.10.3
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
    volumes:
      - ./redis:/data

networks:
  default:
    external:
      name: mastodonnet

SMTP is optional if you don't have an email provider

S3 Media Storage

It is recommended that you enable and configure Mastodon to use an S3 bucket for media. Media storage can easily get to over 100GB.

I'd recommend using Scaleway Object Storage as you get 75GB of Storage and Bandwidth for free.

We'll configure the removal of old media later so you're not storing loads of junk!

Create secrets

Run sudo docker run --rm -it -w /app/www --entrypoint rake lscr.io/linuxserver/mastodon secret

Run the above command twice and store the values under the variables SECRET_KEY_BASE and OTP_SECRET within the docker-compose.yml file.

Create Vapid Keys

Run sudo docker run --rm -it -w /app/www --entrypoint rake lscr.io/linuxserver/mastodon mastodon:webpush:generate_vapid_key

Copy and paste the output into the environmental variables in the docker-compose.yml file.

Example config:

- SECRET_KEY_BASE=20ef02cab8dcdf7a787aa2f1aa29d4414b02c18d97af78ba4860c78bd456edaae4c30a97b846f368e8c58c8625b79d3a9220ea247a4e5e62be1cb1bbbb041705
- OTP_SECRET=20a8013e5fd8d0f2d2d87017e6e6c00fc87fe3d354622b463ff2b40ea42c952459362cb02a7e5fa51c90906546dcd1ecf2de48a2e236944df9070fbee8d190d1
- VAPID_PRIVATE_KEY=M5PjTAf4GbE4zlqAh1lY8NGy1P_JTbCL2i_zly7XOG0=
- VAPID_PUBLIC_KEY=BFRu73k9lDkQUw0pysubc7cpoByCYMm__km6APeLtwrtPPSlWWn064fFjFYAdZ-AiXBRWgWAanB9lm0BP83hBkg=
Start it up!

Run: sudo docker compose up -d

Create your Owner/Admin account:
sudo docker exec -it -w /app/www mastodon bin/tootctl accounts create \
  <YOUR-USERNAME> \
  --email <YOUR-EMAIL> \
  --confirmed \
  --role Owner

A password will be displayed after a few seconds

Reverse Proxy Setup

In order to add TLS (HTTPS) to your Mastodon instance we'll be placing a reverse proxy in front.

We recommend using Caddy however Nginx is a popular alternative.

If you'd like to place your instance behind Cloudflare, follow the Cloudflare Tunnel section.

Caddy

Need to setup Caddy? Follow this guide

mastodon.example.com {
      reverse_proxy https://10.10.10.4  {
                transport http {
                        tls_insecure_skip_verify
                }
        }
}
Cloudflare Tunnel

Need to setup Cloudflare tunnel? Follow this guide
Add the folowing to your config:

  - hostname: mastodon.example.com
    service: https://10.10.10.4:443
    originRequest:
       noTLSVerify: true
Auto removal of old media

Mastodon caches media from other servers, which can potentially use a significant amount of storage.

We'll be using a built-in tool to automatically delete cached media to reduce storage usage.

Open crontab: sudo crontab -e

Add the following:

15 * * * * docker exec -w /app/www mastodon bin/tootctl media remove --days 7 > /dev/null 2>&1

This will run at quater past every hour, removing media that is over 7 days old.

Replace /dev/null if you'd like to store the output to a file.

You'll probably want to adjust the number of days you cache media for.

Enjoy using Mastodon!

Say helloπŸ‘‹
@[email protected]

Tags