Mastodon on a LYLIX VPS — sidekiq scaling, S3-compatible storage, federation traffic
Mastodon is the most-self-hosted Fediverse server. It works fine for a single user; it scales reasonably to a few hundred active users on a single VPS with attention. This article covers the architecture and the production tuning.
Sizing
- Solo instance (just you, federation with the broader Fediverse): 2 GB RAM, 2 CPU, 40 GB disk. Disk is the surprise — media caching from federated servers accumulates.
- Small community (20-100 active users): 4 GB RAM, 4 CPU, 100 GB disk + S3 for media.
- Larger (500+ active): multiple VPSes or scaling tier — beyond a single-box recipe.
The components
- Rails web app — serves the UI and API.
- Streaming server — Node.js, handles WebSocket connections for live updates.
- Sidekiq workers — background jobs: federation delivery, notifications, scheduled posts.
- PostgreSQL — primary data store.
- Redis — queue, cache, rate limits.
- nginx — reverse proxy + TLS.
- Object storage — recommended for media attachments at scale.
Install
Mastodon's official docs walk the Ubuntu install in detail. Summarised:
# Dependencies
apt install postgresql redis-server ruby ruby-bundler \
nodejs yarn nginx imagemagick ffmpeg libpq-dev \
libxml2-dev libxslt1-dev file git-core \
g++ libprotobuf-dev protobuf-compiler pkg-config \
libidn11-dev libicu-dev libjemalloc-dev \
libgdbm-dev libssl-dev libreadline-dev zlib1g-dev
Then clone Mastodon, configure, run the setup wizard, and register systemd units for web, streaming, and sidekiq.
The wizard generates .env.production with all the secrets. Back this file up — losing it loses signing keys, which breaks federation.
Sidekiq — the actually-important part
Sidekiq runs background jobs. The default config is one process with default concurrency. For a busy instance:
# /etc/systemd/system/mastodon-sidekiq.service
Environment="DB_POOL=25"
ExecStart=/path/to/bundle exec sidekiq -c 25
For larger instances, run multiple sidekiq processes with different queue weightings:
default— local actions.push— outbound federation.pull— inbound federation.mailers— email notifications.
# Sidekiq-push.service
ExecStart=... sidekiq -c 20 -q push
# Sidekiq-pull.service
ExecStart=... sidekiq -c 20 -q pull -q default
The "push" queue can back up dramatically when posting to larger followers' federation. Dedicating a process to it prevents user-facing latency.
Object storage for media
Media uploads (images, videos, audio) plus media cached from remote instances will eat disk. Migrate to S3-compatible storage early.
In .env.production:
S3_ENABLED=true
S3_BUCKET=mastodon-media
S3_REGION=us-east-1
S3_ENDPOINT=https://s3.us-west-001.backblazeb2.com
S3_ALIAS_HOST=media.example.com # public CDN endpoint
AWS_ACCESS_KEY_ID=<b2-key-id>
AWS_SECRET_ACCESS_KEY=<b2-key>
Backblaze B2 is significantly cheaper than AWS S3 for media storage. R2 (Cloudflare) is also competitive with no egress fees.
The S3_ALIAS_HOST is critical — set up a CNAME pointing at the bucket (or use the bucket's S3 endpoint directly). Mastodon uses this URL in posts; you don't want to change it later.
Cleanup tasks
Federation cache grows continuously. Schedule cleanup:
# /etc/cron.daily/mastodon-cleanup
#!/bin/bash
cd /home/mastodon/live
RAILS_ENV=production /home/mastodon/.rbenv/shims/bundle exec tootctl media remove --days=14
RAILS_ENV=production /home/mastodon/.rbenv/shims/bundle exec tootctl preview_cards remove --days=14
RAILS_ENV=production /home/mastodon/.rbenv/shims/bundle exec tootctl statuses remove
14 days is typical. Less aggressive means more storage but faster timeline loads for older posts. Tune to your storage budget.
nginx config notes
- WebSocket upgrade required for the streaming endpoint (
/api/v1/streaming). - Large client_max_body_size (40m+) for media uploads.
- Buffering off on the streaming endpoint.
Mastodon's official nginx config example handles all this — use it.
Federation traffic
A solo instance with follows on a few popular accounts can generate surprising traffic. Inbound federation pulls all the posts from followed servers. Watch:
- Disk I/O during federation processing (PostgreSQL).
- Sidekiq queue depth — if pulls are backing up, add sidekiq capacity.
- Outbound bandwidth — federation delivery to thousands of followers' servers.
Database tuning
- shared_buffers = 25% of RAM (PostgreSQL default is too small).
- effective_cache_size = 50-75% of RAM.
- max_connections = match Sidekiq's needs (50+ usually works).
- Enable pg_stat_statements for query analysis if you run into slowness.
Backups
.env.production— the most critical file. If you lose this, federation signing breaks permanently.- PostgreSQL — nightly pg_dumpall.
- Local media (if not on S3).
- system_avatars / system_headers — small but irreplaceable.
Common operational issues
- "Sidekiq is way behind." Add workers and concurrency. Check Redis isn't hitting memory limit.
- "Federation lags by hours." Push queue is backed up. Dedicate a sidekiq process to it.
- "Disk filled overnight." Cleanup tasks not running, or run with too-long retention. Lower retention.
- "Single bad federation peer making instance slow." tootctl can suspend or limit specific instances if they're degrading service.
Also Read
Powered by WHMCompleteSolution