Self-Host Mastodon with Docker Compose
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