Self-Host Mastodon with Docker Compose

Self-Hosting May 12, 2023

Mastodon is a unique social media platform that prioritizes user privacy and community building. Unlike traditional social media networks that are centralized and controlled by a single company, Mastodon is decentralized and consists of a network of independently operated servers, known as instances. This structure allows for greater control over user data and content moderation, and also enables the creation of niche communities centered around specific interests. Users can choose to make their posts public or visible only to their followers, and they have the ability to move between instances or even create their own.

Creating your own Mastodon instance can be a rewarding experience, as it gives you full control over your data and the ability to create a community that aligns with your values and interests. However, it requires some technical knowledge and resources to set up and maintain a server. We'll be covering the basics in this guide using Docker.

Overall, Mastodon offers a refreshing alternative to mainstream social media platforms by putting the power back in the hands of its users. With its decentralized structure and focus on community building, it has the potential to foster a more inclusive and positive online environment.

Requirements

A small instance to support up to 10 users requires at least:
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=
      - SMTP_FROM_ADDRESS=notifications@example.com
      - 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:80
      - 443: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πŸ‘‹
@cyberhost@infosec.exchange

Tags