BlogTutorialsSelf-Host Mastodon and Matrix Server on VPS: The Fediverse Hosting Guide (2026)

Self-Host Mastodon and Matrix Server on VPS: The Fediverse Hosting Guide (2026)

Adrian Silaghi
Adrian Silaghi
April 20, 2026
14 min read
7 views
#mastodon #matrix #fediverse #self-hosted #activitypub #vps #synapse
Self-Host Mastodon and Matrix Server on VPS: The Fediverse Hosting Guide (2026)

In 2026, the centralized social web is finally cracking. Ad-driven feeds, opaque moderation, API shutdowns, and the ongoing enshittification of platforms like X, Reddit, and Discord have pushed an entire generation of users toward something better: the Fediverse.

The Fediverse is a network of independently operated servers that speak open protocols — primarily ActivityPub for microblogging/social (Mastodon, Pleroma, Pixelfed, PeerTube, Lemmy) and Matrix for real-time chat. Each server (an "instance" or "homeserver") is run by a community, a company, or an individual. Users on one server can follow, reply to, and chat with users on any other server in the network — no central authority required.

This guide walks you through self-hosting the two most important pieces of the Fediverse on a single VPS: Mastodon (the Twitter-style social layer) and Matrix/Synapse (the Slack/WhatsApp-style chat layer). By the end, you'll have your own social.yourdomain.com and matrix.yourdomain.com, federated with millions of other users, under your complete control.

What Is the Fediverse?

The Fediverse (a portmanteau of "federated" and "universe") is a collection of interconnected servers running open protocols. Unlike centralized platforms, no single company owns the network. A user on mastodon.social can follow a user on fosstodon.org, and both can chat with someone on matrix.org — all without any of those servers being owned by the same entity.

The two protocols that matter most:

  • ActivityPub — A W3C standard for social networking. Powers Mastodon (microblogging), Pixelfed (photos), PeerTube (video), Lemmy (link aggregation), Bookwyrm (books), and more. Posts on one server are replicated to followers on other servers via "federation".
  • Matrix — A decentralized protocol for real-time chat, voice, and video. Synapse is the reference server; Dendrite is a newer Go-based rewrite. End-to-end encrypted rooms, bridges to Discord/IRC/Telegram/WhatsApp, and a rapidly growing ecosystem.

Think of it like email: you don't need a Gmail account to email someone at Outlook. Same principle — you can run your own server and still talk to everyone else.

Why Self-Host Instead of Using a Hosted Instance?

You have three realistic options:

  1. Join a big public instance — e.g. mastodon.social or matrix.org. Free, zero effort, but you're a guest on someone else's server with their rules, their downtime, and their moderation decisions.
  2. Use managed Fediverse hosting — e.g. masto.host or ungleich.ch. Your own domain, someone else's ops. €6-€19/month for small instances, scales up quickly.
  3. Self-host on your own VPS — Full control, lower per-user cost at scale, but you own the ops.

Here's the comparison that actually matters:

Concern Hosted (mastodon.social, masto.host) Self-Hosted on DanubeData
Monthly cost (single user) €0-€19/mo ~€25-€40/mo all-in
Monthly cost (100 users) €40-€99+/mo (managed) ~€25-€40/mo
Custom domain Paid tiers only Yes, free
Moderation control Follow host's rules Your rules
Data ownership Host has copy You own everything
GDPR controller Host (typically) You (+ DPA with VPS provider)
Migration risk Tied to host Portable, Docker-based
Federation blocks Host decides You decide
Uptime SLA Host-dependent Your responsibility
Custom emoji, themes, relays Limited Unlimited

Self-hosting wins the moment you have more than ~5 users, care about moderation policy, or need GDPR-clean infrastructure inside the EU.

Hardware Sizing: What You Actually Need

Running Mastodon + Matrix on one box is entirely realistic, but the two workloads are different:

  • Mastodon is a Rails app that needs PostgreSQL (user/post data), Redis (queues, cache, home timelines), ElasticSearch (optional, for full-text search), and S3-compatible object storage (for media — this is critical, see below).
  • Matrix/Synapse is a Python app that needs PostgreSQL only. Media is stored on the local filesystem by default, but can be offloaded to S3.

The single biggest mistake new operators make: running Mastodon's media storage on the VPS local disk. A 50-user instance federating with the wider network will accumulate 20-100 GB of cached remote media within weeks — other servers' avatars, header images, attachments — all of which your instance re-downloads because federation is a pull model. Ship media to S3 from day one or you will run out of disk.

Recommended Sizing Table

Instance Size Active Users Workload Recommended VPS DanubeData Plan
Solo / Family 1-5 Mastodon only 2 vCPU / 4 GB / 40 GB NVMe Starter €4.49/mo
Small community 5-25 Mastodon + Matrix 4 vCPU / 8 GB / 80 GB NVMe DD Small €12.49/mo
Medium community 25-250 Mastodon + Matrix + managed PG + S3 8 vCPU / 16 GB / 160 GB NVMe DD Medium €24.99/mo (sweet spot)
Large community 250-2,000 Split: app VPS + managed DB + S3 Dedicated 8 vCPU / 32 GB DD Large / dedicated €49.99+/mo

The sweet spot for most people is DanubeData DD Medium (€24.99/mo) with 8 vCPU, 16 GB RAM, and 160 GB NVMe — enough headroom for Mastodon's Sidekiq workers, Redis, Synapse, and two Postgres instances. Offload media to DanubeData S3 (€3.99/mo, 1 TB included) and you're future-proofed through ~250 active users.

If you want to reduce ops surface, pair the VPS with DanubeData Managed PostgreSQL (€19.99/mo) and Managed Redis (€4.99/mo). That offloads backups, replication, and point-in-time recovery from your shoulders.

Step 1: Provision the VPS and DNS

Before you touch Docker, get the infrastructure ready.

1a. Create the VPS

  1. Sign up at danubedata.ro (new accounts get €50 signup credit — enough to test this entire stack for two months).
  2. Create a VPS: DD Medium (8 vCPU / 16 GB / 160 GB).
  3. Image: Ubuntu 24.04 LTS.
  4. Datacenter: fsn1 (Falkenstein, Germany) — GDPR-safe, low latency to the rest of Europe.
  5. Note the public IPv4 and IPv6 addresses.

1b. DNS Records

You need four A/AAAA records pointing at your VPS:

# DNS records
social.yourdomain.com      A    203.0.113.10   # Mastodon web
social.yourdomain.com      AAAA 2a01:4f8::1    # Mastodon web (IPv6)
matrix.yourdomain.com      A    203.0.113.10   # Synapse
matrix.yourdomain.com      AAAA 2a01:4f8::1    # Synapse (IPv6)
media.yourdomain.com       CNAME s3.danubedata.ro   # Mastodon media (S3 vanity)
element.yourdomain.com     A    203.0.113.10   # Element web client (optional)

Matrix also needs a .well-known file on yourdomain.com (the apex, not matrix.yourdomain.com) so other homeservers can discover yours. We'll set that up in Step 6.

1c. Harden the Server

ssh root@203.0.113.10

# Update
apt update && apt upgrade -y

# Essentials
apt install -y curl wget git ufw fail2ban unattended-upgrades

# Firewall — only 22, 80, 443, and Matrix federation port 8448
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw allow 8448/tcp
ufw enable

# Auto security updates
dpkg-reconfigure --priority=low unattended-upgrades

# Install Docker
curl -fsSL https://get.docker.com | sh
apt install -y docker-compose-plugin
systemctl enable docker

# Create a dedicated user for the stack
adduser --disabled-password --gecos "" fediverse
usermod -aG docker fediverse

# Layout
mkdir -p /opt/fediverse/{mastodon,matrix,caddy}
chown -R fediverse:fediverse /opt/fediverse

Step 2: Provision Object Storage for Mastodon Media

Do this before launching Mastodon. Bolting S3 on later requires a painful migration of existing media.

  1. In the DanubeData dashboard, create a new Object Storage bucket named mastodon-media. Base plan: €3.99/mo with 1 TB storage + 1 TB egress included.
  2. Create an Access Key with read/write permissions on the bucket.
  3. Note the endpoint (https://s3.danubedata.ro), the access key, and the secret key.
  4. Enable public read on the bucket (Mastodon serves media via signed URLs, but public-read is the path of least friction for avatars and header images).

If you own the vanity domain media.yourdomain.com, configure it as a CNAME to your bucket. Mastodon can then serve media from that host, which looks professional and lets you swap S3 backends later without invalidating URLs.

Step 3: Deploy Mastodon with Docker Compose

All configs live under /opt/fediverse/mastodon.

3a. Generate secrets

cd /opt/fediverse/mastodon

# SECRET_KEY_BASE, OTP_SECRET
docker run --rm -it tootsuite/mastodon:v4.3.0 bundle exec rake secret
docker run --rm -it tootsuite/mastodon:v4.3.0 bundle exec rake secret

# VAPID keys for Web Push
docker run --rm -it tootsuite/mastodon:v4.3.0 bundle exec rake mastodon:webpush:generate_vapid_key

Save all four values — you'll paste them into .env.production.

3b. .env.production

cat > /opt/fediverse/mastodon/.env.production << 'EOF'
# Federation
LOCAL_DOMAIN=yourdomain.com
WEB_DOMAIN=social.yourdomain.com
ALTERNATE_DOMAINS=

# Redis
REDIS_HOST=mastodon-redis
REDIS_PORT=6379

# PostgreSQL
DB_HOST=mastodon-db
DB_USER=mastodon
DB_NAME=mastodon_production
DB_PASS=CHANGE_ME_STRONG_PG_PASSWORD
DB_PORT=5432

# ElasticSearch (optional — set ES_ENABLED=false to skip)
ES_ENABLED=true
ES_HOST=mastodon-es
ES_PORT=9200

# Secrets (from step 3a)
SECRET_KEY_BASE=paste_first_secret_here
OTP_SECRET=paste_second_secret_here
VAPID_PRIVATE_KEY=paste_vapid_private_here
VAPID_PUBLIC_KEY=paste_vapid_public_here

# Web Push email contact
WEB_PUSH_CONTACT=admin@yourdomain.com

# SMTP — use Postmark, Mailgun, Amazon SES, or Brevo
SMTP_SERVER=smtp.postmarkapp.com
SMTP_PORT=587
SMTP_LOGIN=your_postmark_token
SMTP_PASSWORD=your_postmark_token
SMTP_FROM_ADDRESS=Mastodon 

# S3 media storage (DanubeData)
S3_ENABLED=true
S3_BUCKET=mastodon-media
S3_REGION=eu-central
S3_PROTOCOL=https
S3_HOSTNAME=s3.danubedata.ro
S3_ENDPOINT=https://s3.danubedata.ro
S3_ALIAS_HOST=media.yourdomain.com
AWS_ACCESS_KEY_ID=your_danubedata_access_key
AWS_SECRET_ACCESS_KEY=your_danubedata_secret_key

# Limits
MAX_TOOT_CHARS=500
SINGLE_USER_MODE=false
DEFAULT_LOCALE=en

# Moderation & safety
TRUSTED_PROXY_IP=172.18.0.0/16
EOF

chmod 600 /opt/fediverse/mastodon/.env.production

3c. docker-compose.yml

cat > /opt/fediverse/mastodon/docker-compose.yml << 'EOF'
services:
  mastodon-db:
    image: postgres:16-alpine
    restart: always
    shm_size: 256mb
    environment:
      POSTGRES_USER: mastodon
      POSTGRES_DB: mastodon_production
      POSTGRES_PASSWORD: CHANGE_ME_STRONG_PG_PASSWORD
    volumes:
      - db:/var/lib/postgresql/data
    networks: [internal]

  mastodon-redis:
    image: redis:7-alpine
    restart: always
    volumes:
      - redis:/data
    networks: [internal]

  mastodon-es:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.17.22
    restart: always
    environment:
      - "discovery.type=single-node"
      - "xpack.security.enabled=false"
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - es:/usr/share/elasticsearch/data
    ulimits:
      memlock: { soft: -1, hard: -1 }
    networks: [internal]

  mastodon-web:
    image: ghcr.io/mastodon/mastodon:v4.3.0
    restart: always
    env_file: .env.production
    command: bundle exec puma -C config/puma.rb
    ports:
      - "127.0.0.1:3000:3000"
    depends_on: [mastodon-db, mastodon-redis, mastodon-es]
    volumes:
      - public-system:/mastodon/public/system
    networks: [internal, web]

  mastodon-streaming:
    image: ghcr.io/mastodon/mastodon-streaming:v4.3.0
    restart: always
    env_file: .env.production
    command: node ./streaming/index.js
    ports:
      - "127.0.0.1:4000:4000"
    depends_on: [mastodon-db, mastodon-redis]
    networks: [internal, web]

  mastodon-sidekiq:
    image: ghcr.io/mastodon/mastodon:v4.3.0
    restart: always
    env_file: .env.production
    command: bundle exec sidekiq
    depends_on: [mastodon-db, mastodon-redis]
    volumes:
      - public-system:/mastodon/public/system
    networks: [internal]

volumes:
  db:
  redis:
  es:
  public-system:

networks:
  internal:
  web:
    name: fediverse-web
EOF

3d. Initialize & launch

cd /opt/fediverse/mastodon

# Pull images
docker compose pull

# Create DB schema
docker compose run --rm mastodon-web bundle exec rails db:setup

# Precompile assets
docker compose run --rm mastodon-web bundle exec rails assets:precompile

# Start everything
docker compose up -d

# Create your admin account
docker compose exec mastodon-web tootctl accounts create admin 
  --email admin@yourdomain.com --confirmed --role Owner

The tootctl command prints a temporary password. Sign in, then change it from the settings page.

Step 4: Deploy Matrix (Synapse) with Docker Compose

Synapse is the reference Matrix homeserver. Dendrite (Go-based rewrite) is lighter but still less feature-complete for admin and moderation in early 2026, so we stick with Synapse.

4a. Generate the config

cd /opt/fediverse/matrix

docker run -it --rm 
  -v /opt/fediverse/matrix/data:/data 
  -e SYNAPSE_SERVER_NAME=yourdomain.com 
  -e SYNAPSE_REPORT_STATS=no 
  matrixdotorg/synapse:latest generate

chown -R fediverse:fediverse /opt/fediverse/matrix/data

Note: SYNAPSE_SERVER_NAME is the user-facing domain, e.g. @alice:yourdomain.com. The HTTP endpoint can still live at matrix.yourdomain.com via .well-known delegation (step 6).

4b. Edit homeserver.yaml

Open /opt/fediverse/matrix/data/homeserver.yaml and set:

# Use Postgres, not SQLite (SQLite does NOT scale)
database:
  name: psycopg2
  args:
    user: synapse
    password: CHANGE_ME_STRONG_SYNAPSE_PG_PASSWORD
    database: synapse
    host: matrix-db
    cp_min: 5
    cp_max: 10

# Disable open registration; invite-only
enable_registration: false
registration_requires_token: true

# Federation
federation_domain_whitelist: null   # null = federate with everyone; list to restrict

# Media retention — keep remote media only 30 days
media_retention:
  remote_media_lifetime: 30d

# URL previews (optional — costs bandwidth)
url_preview_enabled: true
url_preview_ip_range_blacklist:
  - '127.0.0.0/8'
  - '10.0.0.0/8'
  - '172.16.0.0/12'
  - '192.168.0.0/16'

# Trust X-Forwarded-* from Caddy
x_forwarded: true

4c. docker-compose.yml

cat > /opt/fediverse/matrix/docker-compose.yml << 'EOF'
services:
  matrix-db:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_USER: synapse
      POSTGRES_DB: synapse
      POSTGRES_PASSWORD: CHANGE_ME_STRONG_SYNAPSE_PG_PASSWORD
      POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
    volumes:
      - matrix-db:/var/lib/postgresql/data
    networks: [internal]

  synapse:
    image: matrixdotorg/synapse:latest
    restart: always
    depends_on: [matrix-db]
    ports:
      - "127.0.0.1:8008:8008"
      - "127.0.0.1:8448:8448"
    volumes:
      - ./data:/data
    networks: [internal, web]

volumes:
  matrix-db:

networks:
  internal:
  web:
    name: fediverse-web
    external: true
EOF

cd /opt/fediverse/matrix
docker compose up -d

# Create an admin user
docker compose exec synapse register_new_matrix_user 
  -u admin -a -c /data/homeserver.yaml http://localhost:8008

Step 5: Reverse Proxy + SSL with Caddy

Caddy gives us automatic Let's Encrypt certs, HTTP/2, and clean config. It also handles the Matrix federation port on 8448.

cat > /opt/fediverse/caddy/Caddyfile << 'EOF'
# Mastodon web + streaming
social.yourdomain.com {
    encode gzip zstd

    handle /api/v1/streaming/* {
        reverse_proxy 127.0.0.1:4000
    }

    handle {
        reverse_proxy 127.0.0.1:3000
    }

    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options nosniff
        Referrer-Policy strict-origin-when-cross-origin
    }
}

# Matrix client-server API
matrix.yourdomain.com {
    reverse_proxy 127.0.0.1:8008
}

# Matrix federation on 8448
matrix.yourdomain.com:8448 {
    reverse_proxy 127.0.0.1:8448
}

# .well-known delegation (served from the apex)
yourdomain.com {
    root * /opt/fediverse/caddy/well-known
    file_server

    # Matrix delegation
    @matrix path /.well-known/matrix/*
    header @matrix Content-Type application/json
    header @matrix Access-Control-Allow-Origin *

    # Mastodon host-meta
    @hostmeta path /.well-known/host-meta
    redir @hostmeta https://social.yourdomain.com/.well-known/host-meta 301

    # Webfinger
    @webfinger path /.well-known/webfinger*
    redir @webfinger https://social.yourdomain.com{uri} 301
}
EOF

# .well-known JSON files for Matrix
mkdir -p /opt/fediverse/caddy/well-known/.well-known/matrix

cat > /opt/fediverse/caddy/well-known/.well-known/matrix/server << 'EOF'
{"m.server": "matrix.yourdomain.com:8448"}
EOF

cat > /opt/fediverse/caddy/well-known/.well-known/matrix/client << 'EOF'
{
  "m.homeserver": {"base_url": "https://matrix.yourdomain.com"},
  "m.identity_server": {"base_url": "https://vector.im"}
}
EOF

# Run Caddy
docker run -d --name caddy --restart always 
  --network fediverse-web 
  -p 80:80 -p 443:443 -p 8448:8448 
  -v /opt/fediverse/caddy/Caddyfile:/etc/caddy/Caddyfile 
  -v /opt/fediverse/caddy/well-known:/opt/fediverse/caddy/well-known 
  -v caddy-data:/data 
  -v caddy-config:/config 
  caddy:2-alpine

Verify both domains are issuing certs:

curl -I https://social.yourdomain.com
curl -I https://matrix.yourdomain.com
curl https://yourdomain.com/.well-known/matrix/server

Step 6: Federation Sanity Checks

Federation is what makes the Fediverse a verse. If you skip these checks, you'll end up invisible to the rest of the network.

Mastodon federation

  1. Visit https://social.yourdomain.com and search for an external account (e.g. @Gargron@mastodon.social). It should resolve and show their posts.
  2. Follow a couple of external accounts. Within 10-30 seconds their toots should appear in your home timeline.
  3. Test the inbound direction: from another account on another instance, search for @you@yourdomain.com. It should resolve (the LOCAL_DOMAIN and WEB_DOMAIN split is critical here).

Matrix federation

Use the official Federation Tester:

https://federationtester.matrix.org/#yourdomain.com

All checks should be green. The common failures:

  • SRV or well-known missing — re-check /.well-known/matrix/server.
  • Port 8448 unreachable — re-check UFW and the Caddy :8448 block.
  • Certificate name mismatch — Caddy must be issuing certs for yourdomain.com, not just matrix.yourdomain.com.

Step 7: Moderation Tooling

Running an instance = making moderation decisions. Tools you need to know about:

Mastodon

  • Admin UI (social.yourdomain.com/admin) — reports, accounts, federation (defederate / silence other domains).
  • tootctl — CLI for pruning cached media, cleaning up orphaned files, bulk-moderating domains:
    docker compose exec mastodon-web tootctl media remove --days 14
    docker compose exec mastodon-web tootctl domains purge badguy.example
    
  • Domain block lists — import community-maintained lists from fediblock.org to pre-emptively defederate known bad actors.
  • Report routing — enable email notifications for new reports (ADMIN_EMAIL in .env).

Matrix

  • Synapse Admin APIsynapse-admin is a web UI that wraps the admin API. Deploy it behind auth at admin.matrix.yourdomain.com.
  • Mjolnir (now superseded by Draupnir) — an anti-abuse bot that joins rooms you flag and enforces policy lists shared across homeservers. Essential for community servers.
  • Community moderation policy lists — subscribe to shared policy lists to inherit block rulings from trusted operators.

Practical tip: publish your server rules page from day one (/about on Mastodon, a pinned room on Matrix). This is a federation hygiene requirement — other admins look at your rules before deciding whether to federate with you.

Step 8: Bandwidth and Federation Egress

Federation is chatty. Every local post is fanned out to every server that has at least one follower of the author. Every remote post you see has been delivered to your inbox. Every media attachment (image, video) is either cached locally or hot-linked.

Rough bandwidth estimates for Mastodon:

Instance size Estimated monthly egress Estimated monthly ingress
Solo (1 user, 500 follows) 1-5 GB 20-80 GB
Small (10 users, 5k follows) 10-50 GB 100-500 GB
Medium (100 users, 50k follows) 100-500 GB 500 GB-2 TB

Matrix is lighter in text-only rooms but heavier if your users join large Space-shared rooms with history backfill.

DanubeData includes 20 TB of traffic per VPS, which covers even a large self-hosted Fediverse setup comfortably. Overages are €1.21/TB — still dramatically cheaper than AWS (€80+/TB) or DigitalOcean (~€9/TB).

For S3 egress, DanubeData Object Storage includes 1 TB/month in the €3.99/mo base. If you front media with Cloudflare's free tier (legal for media caching under their TOS), you can serve most avatar/header traffic from edge cache and drastically reduce origin egress.

Step 9: Backups

You now have two Postgres databases, one Redis instance, and one S3 bucket. Back them all up.

cat > /opt/fediverse/backup.sh << 'EOF'
#!/bin/bash
set -e

BACKUP_DIR="/opt/fediverse/backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
S3_BACKUP_BUCKET="fediverse-backups"

mkdir -p "$BACKUP_DIR"

echo "=== Fediverse Backup: $DATE ==="

# Mastodon Postgres
docker compose -f /opt/fediverse/mastodon/docker-compose.yml exec -T mastodon-db 
  pg_dump -U mastodon mastodon_production | gzip > "$BACKUP_DIR/mastodon_pg_$DATE.sql.gz"

# Matrix Postgres
docker compose -f /opt/fediverse/matrix/docker-compose.yml exec -T matrix-db 
  pg_dump -U synapse synapse | gzip > "$BACKUP_DIR/synapse_pg_$DATE.sql.gz"

# Mastodon Redis (RDB snapshot)
docker compose -f /opt/fediverse/mastodon/docker-compose.yml exec -T mastodon-redis 
  redis-cli SAVE
docker cp mastodon-mastodon-redis-1:/data/dump.rdb "$BACKUP_DIR/redis_$DATE.rdb"

# Matrix media (local filesystem)
tar -czf "$BACKUP_DIR/matrix_media_$DATE.tar.gz" 
  -C /opt/fediverse/matrix/data media_store signing.key homeserver.yaml

# Config files
cp /opt/fediverse/mastodon/.env.production "$BACKUP_DIR/mastodon_env_$DATE"
cp /opt/fediverse/matrix/data/homeserver.yaml "$BACKUP_DIR/synapse_yaml_$DATE"

# Upload to S3 via rclone
rclone copy "$BACKUP_DIR" "danubedata:$S3_BACKUP_BUCKET/$(date +%Y/%m)/" 
  --include "*$DATE*"

# Retain 7 days locally
find "$BACKUP_DIR" -type f -mtime +7 -delete

echo "=== Backup complete ==="
EOF

chmod +x /opt/fediverse/backup.sh

# Schedule daily at 03:00
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/fediverse/backup.sh >> /var/log/fediverse-backup.log 2>&1") | crontab -

For Mastodon S3 media, use Object Storage's built-in versioning or cross-region replication if your threat model requires it. Most operators don't back up media explicitly — if the bucket is lost, federation will gradually re-fetch remote media on demand, and local user uploads are the only truly critical loss (hence versioning).

Step 10: Ongoing Maintenance

Weekly cron tasks

# Clean Mastodon media cache (older than 14 days)
0 4 * * 0 docker compose -f /opt/fediverse/mastodon/docker-compose.yml exec -T mastodon-web tootctl media remove --days 14

# Clean orphaned statuses
0 5 * * 0 docker compose -f /opt/fediverse/mastodon/docker-compose.yml exec -T mastodon-web tootctl statuses remove

# Rotate Synapse access tokens for inactive users
# (run via synapse-admin UI or API as needed)

Monitoring

At minimum, monitor:

  • Disk usage on the VPS (alert at 80%)
  • Postgres connections (Mastodon's Sidekiq can spike this)
  • Redis memory
  • S3 bucket size and object count
  • Sidekiq queue depth (visible at /sidekiq)

Uptime Kuma is a one-container solution that covers external health checks for both your Mastodon and Matrix endpoints.

GDPR and Legal Considerations

Running a Fediverse instance in the EU (including Germany) makes you a data controller under GDPR. Concretely:

  • Privacy policy — Mandatory. Mastodon has a built-in /about/more section; populate it.
  • Data subject rights — Users can request export (Mastodon's "Download your archive" feature handles this) and deletion (built into both platforms).
  • DPA with your VPS provider — DanubeData provides a standard DPA; sign it before going live. DanubeData's Falkenstein datacenter means data stays in the EU by default.
  • Breach notification — 72-hour rule. Have an incident plan.
  • Federation — By federating, you're transmitting pseudonymous user data (posts, follows, reactions) to other servers. Document this in your privacy policy as a lawful transfer under legitimate interest (Art. 6(1)(f)).
  • Moderation logs — Keep them, but minimize what you log about user content. Admin actions need an audit trail.

If you're running for commercial purposes (charging users, selling ads, accepting donations via a company), consult a lawyer. Personal/hobby instances have a lower bar, but GDPR still applies the moment you have a second user.

Scaling Beyond One Box

A single DD Medium VPS handles roughly 250 active Mastodon users + 100 active Matrix users comfortably. Past that, you'll want to split:

  1. Move Postgres to DanubeData Managed PostgreSQL — €19.99/mo per instance. Gives you automated backups, read replicas, and point-in-time recovery. Mastodon and Synapse should each have their own managed DB.
  2. Move Redis to DanubeData Managed Redis — €4.99/mo. Mastodon is very sensitive to Redis latency; managed gives you HA.
  3. Split Sidekiq workers onto a separate VPS — Mastodon's sidekiq container can run on a dedicated DD Small. This keeps the web tier responsive during federation storms.
  4. ElasticSearch on its own VPS — Only if search is heavily used. Most instances can run with ES_ENABLED=false.

At ~1,000 active users, your monthly bill is still around €100/mo. The equivalent managed Mastodon hosting (masto.host Professional plus add-ons) would be €150-€300/mo with less flexibility.

FAQ

How much does it actually cost to self-host Mastodon + Matrix for a small community?

For 10-50 active users, the realistic 2026 monthly cost on DanubeData is: DD Medium VPS (€24.99) + S3 bucket (€3.99) = €28.98/mo. Add Managed PostgreSQL (€19.99) if you want managed database backups, for a total of €48.97/mo. The €50 signup credit covers your first month free.

Do I really have to moderate? Can't I just let federation sort itself out?

No. Running an instance means you are legally and ethically on the hook for content. Other admins will defederate your server if you don't respond to reports. At minimum: a written rules page, a reachable admin email, weekly review of the reports queue, and a policy on how you handle illegal content (CSAM reporting to authorities is mandatory in the EU). Plan for 30-60 minutes/week of moderation work for a small instance; more if you accept open signups.

What are my GDPR obligations if I run an instance in Germany?

You are the controller for user data stored on your server. You need a privacy policy, a way for users to export and delete their data (both Mastodon and Synapse support this natively), a DPA with your VPS provider (DanubeData provides one), and a breach notification plan. Federation itself is generally covered under legitimate interest but must be disclosed. Don't charge money or accept donations without consulting a lawyer first — the bar goes up.

Can I scale a single VPS to thousands of users?

Not realistically. Around 250-500 active users, you'll hit Postgres contention and Sidekiq queue lag. The standard scale path is: (1) move databases to managed services, (2) split Sidekiq onto its own VPS, (3) front media with a CDN. DanubeData's DD Large with managed Postgres + managed Redis handles ~2,000 active users; beyond that, you're looking at dedicated hardware (DD's dedicated-CPU tier) and a dedicated Sidekiq VPS. A good rule of thumb: if you're hitting limits, it's almost always Postgres first.

What are the real risks of federation?

Three categories: abuse (your users being harassed by accounts on other servers — handle via reports + domain blocks), spam waves (a hostile instance fans out abuse to 10k users — defederate on sight), and reputational (if your instance hosts bad content, other admins block you and your users become unreachable). The mitigation is a clear rules page, fast moderation response, and subscribing to community block lists (fediblock.org for Mastodon, Draupnir policy lists for Matrix).

Mastodon vs. Pleroma vs. Akkoma vs. GoToSocial — which should I run?

For most people in 2026: Mastodon. It has the biggest community, the largest pool of mod tools, the most official apps, and the most stable release cadence. Akkoma is lighter on resources (runs comfortably on a Starter €4.49 VPS for a single user) and has feature flexibility Mastodon lacks, but the ecosystem is smaller. GoToSocial is extremely light (Go binary, no Ruby/Rails overhead) and ideal for solo use, but still pre-1.0 as of early 2026 — fine for hobby, risky for community.

Synapse vs. Dendrite vs. Conduit — which Matrix server?

Synapse in 2026 — it's the reference, has the best admin tooling, and all major Matrix features land there first. Dendrite (Go) is lighter and great for solo/family use but still missing some enterprise features. Conduit (Rust) is the lightest of the three (can run on an ARM Raspberry Pi) and perfect for personal use, but federation compatibility with large homeservers still has rough edges.

What happens to my users if my server goes down permanently?

Mastodon users can migrate their account to another instance, taking their followers with them (but not their posts — posts stay with the instance). Matrix users can export their rooms' encrypted keys and rejoin rooms on a new homeserver, though message history retrieval depends on other homeservers still having it. Moral: don't run a community instance you can't commit to maintaining for at least 2-3 years, and have a public deprecation policy.

Wrapping Up

The Fediverse in 2026 is no longer a tech-curiosity sideshow. Millions of active users, a mature protocol ecosystem, and a steady exodus from centralized platforms mean self-hosting a Mastodon + Matrix stack is a legitimate infrastructure decision, not just a hobby project.

The recipe that works:

  • DanubeData DD Medium VPS (€24.99/mo) — 8 vCPU, 16 GB, 160 GB NVMe in Falkenstein.
  • DanubeData Object Storage (€3.99/mo) — 1 TB media storage, S3-compatible, EU-hosted.
  • Optional: DanubeData Managed PostgreSQL (€19.99/mo) — offload DB ops.
  • 20 TB included traffic — covers federation egress for most instances.
  • €50 signup credit — your first two months are effectively free.

Total realistic cost: €28.98-€48.97/mo for a community of 10-50 users, entirely under your control, with data stored inside the EU.

Ready to plant your flag in the Fediverse?

  1. Create a DanubeData account and claim your €50 signup credit.
  2. Provision a DD Medium VPS in Falkenstein.
  3. Follow this guide end-to-end. Plan half a day for the full setup.
  4. Announce your instance. Write up your rules. Subscribe to a community block list. You're live.

👉 Launch Your Fediverse Server on DanubeData

Questions about sizing, federation, or production hardening? Reach out to our team — we run Fediverse infrastructure ourselves and are happy to help you pick the right shape.

Share this article

Ready to Get Started?

Deploy your infrastructure in minutes with DanubeData's managed services.