Self-Hosting Mastodon: Run Your Own Fediverse Social Media Instance
Running your own social media server sounds like an absurd amount of work for a marginal benefit. And honestly, for most people it is. But there are legitimate reasons to self-host a Mastodon instance: you want to own your online identity, you need a branded presence for a community or organization, or you simply want to participate in the fediverse on your own terms. Before you commit, you should understand what you're signing up for — this guide covers both the how and the honest operational reality.
Mastodon is an open source, decentralized social media platform that implements the ActivityPub protocol. It looks and feels similar to Twitter, with posts (called "toots" originally, now just "posts"), followers, timelines, and hashtags. The key difference is federation: your Mastodon instance communicates with thousands of other Mastodon instances, plus Lemmy, Pixelfed, PeerTube, and anything else that speaks ActivityPub. Your account on your server can interact with users on any federated server.
How Federation Works
The fediverse operates like email: your Mastodon instance is like your email server. You have an address (@[email protected]), and you can send messages to anyone on any other instance, just like [email protected] can email [email protected].
When you follow someone on a remote instance:
- Your instance sends a follow request to their instance via ActivityPub
- Their instance accepts and starts forwarding their posts to your instance
- Your instance stores copies of their posts for your timeline
- Replies, boosts, and favorites are all federated back and forth
This means your instance stores not only your posts but also cached copies of everything your users follow. This has significant storage implications (more on that later).
The timeline types
- Home — posts from people you follow (local and remote)
- Local — posts from users on your specific instance
- Federated — posts from all instances your server has seen (can be noisy)
Mastodon vs. GoToSocial vs. Akkoma vs. Misskey
| Feature | Mastodon | GoToSocial | Akkoma | Misskey |
|---|---|---|---|---|
| Protocol | ActivityPub | ActivityPub | ActivityPub | ActivityPub |
| Language | Ruby on Rails | Go | Elixir | Node.js |
| RAM (idle) | 1-2 GB | 100-250 MB | 500 MB-1 GB | 500 MB-1 GB |
| Storage growth | High | Low-Moderate | Moderate | Moderate |
| Web UI | Yes (Glitch-soc fork popular) | No (use third-party clients) | Yes (Pleroma-based) | Yes (unique UI) |
| Mobile apps | Many (Ivory, Ice Cubes, Tusky, etc.) | Mastodon-compatible apps | Mastodon-compatible apps | Misskey-specific apps |
| Character limit | 500 (configurable) | 5,000 (default) | Configurable | 3,000 (default) |
| Custom emoji | Yes | Yes | Yes | Yes |
| Reactions | Favorites only | Favorites only | Emoji reactions | Emoji reactions |
| Quote posts | No (controversial) | No | Yes | Yes |
| Admin UI | Web-based | Limited (CLI + settings) | Web-based | Web-based |
| Moderation tools | Excellent | Basic | Good | Good |
| Single-user friendly | Not ideal | Excellent | Good | Not ideal |
| Maturity | Most mature | Newer (active dev) | Mature (Pleroma fork) | Mature |
| Full-text search | Elasticsearch/optional | Built-in | Built-in | Built-in |
Which to choose
Mastodon is the default choice if you want the widest ecosystem of mobile apps, the most robust moderation tools, and the strongest community. It's also the heaviest.
GoToSocial is the best choice for single-user instances or small groups. It uses a fraction of the resources and has no web UI — you interact entirely through Mastodon-compatible apps like Ivory or Tusky. If you just want your own fediverse identity without running a full social network, GoToSocial is the practical choice.
Akkoma (a fork of Pleroma) is a good middle ground — lighter than Mastodon, more features than GoToSocial, with quote posts and emoji reactions.
Misskey offers a different UI paradigm with features Mastodon deliberately omits (quote posts, reactions, a drive for file management). It has a strong following in Japan.
Self-Hosting Mastodon: Setup
Server requirements
Mastodon is resource-intensive compared to most self-hosted applications:
- Minimum: 2 GB RAM, 2 CPU cores, 20 GB storage
- Recommended: 4 GB RAM, 2 CPU cores, 50+ GB storage
- Storage warning: media cache grows continuously — plan for 1-5 GB/month for a single-user instance, much more for multi-user
Docker Compose setup
Mastodon requires several services: the web frontend, the streaming server, Sidekiq background workers, PostgreSQL, Redis, and optionally Elasticsearch.
services:
mastodon-web:
container_name: mastodon-web
image: ghcr.io/mastodon/mastodon:latest
command: bundle exec puma -C config/puma.rb
ports:
- "3000:3000"
environment: &mastodon-env
LOCAL_DOMAIN: "social.yourdomain.com"
REDIS_HOST: "redis"
DB_HOST: "postgres"
DB_USER: "mastodon"
DB_PASS: "mastodon"
DB_NAME: "mastodon"
SECRET_KEY_BASE: "generate-with-rake-secret"
OTP_SECRET: "generate-with-rake-secret"
VAPID_PRIVATE_KEY: "generate-with-rake-task"
VAPID_PUBLIC_KEY: "generate-with-rake-task"
SMTP_SERVER: "smtp.yourdomain.com"
SMTP_PORT: "587"
SMTP_LOGIN: "[email protected]"
SMTP_PASSWORD: "your-smtp-password"
SMTP_FROM_ADDRESS: "[email protected]"
S3_ENABLED: "false"
volumes:
- mastodon-public:/opt/mastodon/public/system
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
restart: always
mastodon-streaming:
container_name: mastodon-streaming
image: ghcr.io/mastodon/mastodon:latest
command: node ./streaming/index.js
ports:
- "4000:4000"
environment:
<<: *mastodon-env
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
restart: always
mastodon-sidekiq:
container_name: mastodon-sidekiq
image: ghcr.io/mastodon/mastodon:latest
command: bundle exec sidekiq
environment:
<<: *mastodon-env
volumes:
- mastodon-public:/opt/mastodon/public/system
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
restart: always
postgres:
container_name: mastodon-db
image: postgres:16-alpine
environment:
POSTGRES_DB: "mastodon"
POSTGRES_USER: "mastodon"
POSTGRES_PASSWORD: "mastodon"
volumes:
- mastodon-db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mastodon"]
interval: 10s
timeout: 5s
retries: 5
restart: always
redis:
container_name: mastodon-redis
image: redis:7-alpine
volumes:
- mastodon-redis:/data
restart: always
volumes:
mastodon-public:
mastodon-db:
mastodon-redis:
Generating secrets
Before starting, generate the required secrets:
# Generate SECRET_KEY_BASE and OTP_SECRET
docker run --rm ghcr.io/mastodon/mastodon:latest bundle exec rake secret
# Run this twice — once for SECRET_KEY_BASE, once for OTP_SECRET
# Generate VAPID keys
docker run --rm ghcr.io/mastodon/mastodon:latest bundle exec rake mastodon:webpush:generate_vapid_key
Database setup
Initialize the database before first run:
docker compose run --rm mastodon-web bundle exec rake db:setup
Creating your admin account
docker compose run --rm mastodon-web bin/tootctl accounts create \
yourusername \
--email [email protected] \
--confirmed \
--role Owner
Starting the service
docker compose up -d
Access Mastodon at http://your-server:3000. You'll need a reverse proxy for production use.
Reverse Proxy Setup
Mastodon requires a reverse proxy that handles both the web interface and the streaming API:
Caddy:
social.yourdomain.com {
handle /api/v1/streaming* {
reverse_proxy localhost:4000
}
handle {
reverse_proxy localhost:3000
}
}
Nginx:
server {
server_name social.yourdomain.com;
client_max_body_size 80M;
location / {
proxy_pass http://localhost:3000;
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;
}
location /api/v1/streaming {
proxy_pass http://localhost:4000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
proxy_redirect off;
}
}
Instance Administration
Site settings
In the admin panel (Preferences > Administration > Server Settings):
- Server rules — define your instance's community guidelines
- Registration mode — open, approval-required, or invite-only
- Custom extended description — explain what your instance is about
- Thumbnail and hero images — brand your instance
- Contact info — who to email for issues
For single-user instances, set registration to closed after creating your account.
Moderation
Mastodon's moderation tools are the most mature in the fediverse:
- Block domains — prevent all interaction with a specific instance
- Silence domains — hide content from an instance unless users explicitly follow accounts there
- Suspend users — remove individual remote accounts from your instance
- Report handling — review and act on reports from your users
- Audit log — track all moderation actions
Relay setup
Relays broadcast posts between instances, filling your federated timeline with content. Without relays or active following, a new instance's federated timeline will be empty.
To add a relay:
- Go to Administration > Relays
- Add a relay URL (e.g.,
https://relay.fedi.buzz/instance/yourdomain.com) - Wait for the relay to accept your instance
Popular relays include relay.fedi.buzz (topic-based) and relay.intahnet.co.uk. Be selective — relays increase both network traffic and storage usage.
Storage Management
Storage is the biggest ongoing challenge of running a Mastodon instance. Every remote post your users see, every avatar, every image preview gets cached on your server.
Media cache cleanup
Run periodic cleanups to remove cached remote media:
# Remove remote media cache older than 7 days
docker compose exec mastodon-web bin/tootctl media remove --days=7
# Remove preview cards older than 14 days
docker compose exec mastodon-web bin/tootctl preview_cards remove --days=14
# Remove orphaned media
docker compose exec mastodon-web bin/tootctl media remove-orphans
Automating cleanup with cron
Add a cron job to run cleanup regularly:
# Run media cleanup daily at 3 AM
0 3 * * * cd /path/to/mastodon && docker compose exec -T mastodon-web bin/tootctl media remove --days=7
0 4 * * * cd /path/to/mastodon && docker compose exec -T mastodon-web bin/tootctl preview_cards remove --days=14
S3 object storage
For larger instances, offloading media to S3-compatible storage (AWS S3, MinIO, Cloudflare R2, Wasabi) is strongly recommended:
environment:
S3_ENABLED: "true"
S3_BUCKET: "mastodon-media"
AWS_ACCESS_KEY_ID: "your-key"
AWS_SECRET_ACCESS_KEY: "your-secret"
S3_REGION: "us-east-1"
S3_HOSTNAME: "s3.amazonaws.com"
S3_PROTOCOL: "https"
Object storage keeps your local disk manageable and makes media serving faster through CDN integration.
The Honest Operational Reality
Running a Mastodon instance is more like running a small web service than installing a typical self-hosted application. Here's what ongoing operation actually looks like:
What goes well
- The software itself is stable and well-maintained
- The Docker deployment works reliably
- Federation mostly "just works" once set up
- The mobile app ecosystem is excellent (Ivory, Ice Cubes, Tusky, Moshidon)
What requires ongoing attention
- Storage grows continuously — media cache cleanup must be automated
- Updates matter — security patches and federation protocol changes mean you should update regularly
- Sidekiq queues — background jobs can fall behind, especially on underpowered hardware
- Email delivery — Mastodon needs working SMTP for notifications and account management
- SSL certificates — federation breaks if your HTTPS certificate expires
- Database maintenance — PostgreSQL needs periodic vacuuming and backups
What catches people off guard
- A single-user instance still processes federation traffic for everyone you follow
- The initial federated timeline will be empty — it takes time to build connections
- Migrating your account to another instance is possible but not seamless
- If your instance goes down for extended periods, federation peers may stop delivering to you
Backup Strategy
# Database backup
docker compose exec -T mastodon-db pg_dump -U mastodon mastodon > mastodon-backup-$(date +%Y%m%d).sql
# Volume backup (local media)
docker run --rm -v mastodon-public:/data -v $(pwd):/backup alpine tar czf /backup/mastodon-media-$(date +%Y%m%d).tar.gz /data
For the database, daily backups are recommended. For media, if you're using S3, the object storage handles durability — just back up the database.
Honest Trade-offs
Mastodon is the right choice if you:
- Want the widest mobile app compatibility in the fediverse
- Need robust moderation tools (for multi-user instances)
- Want the most mature, well-tested fediverse server
- Are comfortable with the operational overhead
- Want to be part of the largest fediverse network
Consider GoToSocial instead if you:
- Want a single-user or small-group fediverse presence
- Have limited server resources (GoToSocial uses 10-20% of Mastodon's resources)
- Don't need a web UI (you'll use mobile apps)
- Want lower maintenance burden
- Just want your own fediverse identity, not a social network
Consider Akkoma instead if you:
- Want quote posts and emoji reactions
- Prefer a lighter server than Mastodon
- Want a Pleroma-based experience with more features
- Run a small-to-medium community
Consider Misskey instead if you:
- Want a different UI paradigm with drive, reactions, and channels
- Want quote posts and more expressive interaction options
- Are comfortable with a less common platform
The bottom line: Self-hosting Mastodon is a commitment. It's not like spinning up a Nextcloud instance and forgetting about it — federation adds complexity, storage grows, and the system needs regular attention. For organizations and communities that want their own identity on the fediverse, it's the gold standard. For individuals who just want a fediverse account, joining an existing instance or running GoToSocial is usually more practical. Know what you're getting into before you start, and you'll be fine.