Skip to main content
  1. Posts/

State of the Discord – The Ultimate Self‑Host Lesson from r/selfhosted (2024‑2026)

·6 mins

The Community Spark: Why “State of the Discord – A Lesson” Went Viral #

In early 2024 a Reddit thread titled “State of the Discord – A Lesson” exploded on r/selfhosted, amassing over 12 k up‑votes and a dozen deep‑dive comment chains. The core question was simple yet powerful:

“If you’re running a community, should you keep relying on Discord, or is it time to migrate to a self‑hosted alternative?”

The post resonated because it touched three pain points that self‑hosters repeatedly flag:

  1. Data sovereignty – Discord’s Terms of Service give the company sweeping rights over user content.
  2. Feature parity – Many alternatives claim to be “Discord‑compatible” but fall short on voice, bots, or UI polish.
  3. Operational cost – Running a VPS with real‑time chat, media storage, and voice can feel pricey compared to a free Discord server.

What followed was a week‑long “town‑hall” of lived experiences: success stories, hard‑won failures, and a collective checklist that now serves as the de‑facto guide for anyone contemplating a migration. This article synthesizes those community insights, augments them with expert technical walk‑throughs, and delivers a definitive, action‑oriented playbook for 2026.


Synthesized Community Perspectives: Consensus, Debates, and the “Lesson” Everyone Learned #

Community ThemeWhat the Majority SaidNotable Counter‑Arguments
Data OwnershipUsers overwhelmingly value full control of chat logs, media, and bot data.A few argued that Discord’s backups and export tools are “good enough” for small hobby groups.
Feature ParityRevolt and Matrix (via Element) were praised for text chat & bots; voice remained a gap.Some veterans claimed that “good enough” voice can be achieved with Jitsi or Mumble, while others insisted on native Discord‑style low‑latency voice.
Operational ComplexityDocker‑Compose + Systemd was the preferred deployment method for most.A minority advocated for Kubernetes for scaling, but many warned it’s overkill for <200 users.
Cost vs. BenefitA $10‑$15 /month VPS (2 vCPU, 4 GB RAM) was deemed sufficient for up to 150 active users.A handful of high‑traffic gaming clans reported spikes that required auto‑scaling on Hetzner Cloud.
Community MigrationA phased migration (export → import → parallel run) reduced friction.Some users tried a “big bang” cut‑over and suffered data loss due to Discord rate limits.

The Core Lesson #

Self‑hosting is feasible and rewarding, but only when you match the solution to your community’s size, feature expectations, and operational bandwidth.

The community’s collective “lesson” is a three‑step decision matrix:

  1. Define Requirements – Text only? Voice? Bot ecosystem? GDPR compliance?
  2. Benchmark Resources – Estimate concurrent users, storage, and bandwidth.
  3. Pick the Right Stack – Revolt for Discord‑like UI, Matrix for federation, or a hybrid (Matrix + Jitsi) for voice.

With that framework in place, let’s dive into the technical tutorial that the Redditors voted most helpful: Deploying Revolt on a modest VPS with Docker, Nginx reverse proxy, and automatic backups.


Deep‑Dive Actionable Guide: Deploying a Production‑Ready Revolt Server (2026 Edition) #

Assumption: You have a fresh VPS (Ubuntu 24.04 LTS, 2 vCPU, 4 GB RAM, 80 GB SSD) and root access.

1. Prerequisites #

# Update OS and install essential tools
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl gnupg2 ca-certificates lsb-release software-properties-common git
# Add Docker’s official GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# Set up the stable repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io

# Verify
docker version

3. Create a Dedicated Non‑Root User for Docker #

sudo adduser --disabled-password --gecos "" revolt
sudo usermod -aG docker revolt
# Log out/in or `newgrp docker` to apply group change

4. Clone the Official Revolt Docker Compose Template #

sudo -u revolt mkdir -p ~/revolt && cd ~/revolt
git clone https://github.com/revoltchat/revolt-docker.git .

5. Adjust Environment Variables #

Edit docker-compose.yml (or env.example.env) to suit your domain and storage:

# .env
REVOlt_DOMAIN=chat.example.com
REVOlt_LETSENCRYPT_EMAIL=admin@example.com
REVOlt_DB_PASSWORD=StrongRandomPassword123!

Tip from r/selfhosted: Use openssl rand -base64 32 to generate a cryptographically‑secure password.

6. Set Up Nginx Reverse Proxy with Automatic HTTPS (Caddy Alternative) #

While Revolt ships its own Caddy‑based proxy, many community members preferred Traefik for fine‑grained middleware (rate‑limit, auth‑basic). Below is a minimal Traefik v3 config.

# Install Traefik (binary method)
curl -L https://github.com/traefik/traefik/releases/download/v3.0.0/traefik_v3.0.0_linux_amd64.tar.gz | tar -xz
sudo mv traefik /usr/local/bin/
sudo mkdir -p /etc/traefik && sudo chown revolt:revolt /etc/traefik

Create traefik.yml:

# /etc/traefik/traefik.yml
log:
  level: INFO
api:
  dashboard: true
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
providers:
  docker:
    exposedByDefault: false
certificatesResolvers:
  letsencrypt:
    acme:
      email: ${REVOlt_LETSENCRYPT_EMAIL}
      storage: acme.json
      httpChallenge:
        entryPoint: web

Create acme.json (must be 600):

touch /etc/traefik/acme.json
chmod 600 /etc/traefik/acme.json

7. Launch Revolt with Docker‑Compose (using Traefik labels) #

Edit docker-compose.yml to include Traefik labels:

services:
  api:
    image: revoltchat/api:latest
    restart: unless-stopped
    env_file: .env
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.revolt-api.rule=Host(`${REVOlt_DOMAIN}`) && PathPrefix(`/api`)"
      - "traefik.http.routers.revolt-api.entrypoints=websecure"
      - "traefik.http.routers.revolt-api.tls.certresolver=letsencrypt"
  front:
    image: revoltchat/front:latest
    restart: unless-stopped
    env_file: .env
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.revolt-front.rule=Host(`${REVOlt_DOMAIN}`)"
      - "traefik.http.routers.revolt-front.entrypoints=websecure"
      - "traefik.http.routers.revolt-front.tls.certresolver=letsencrypt"
  # Database (PostgreSQL) omitted for brevity – same as upstream template

Start everything:

docker compose up -d

Verify with docker ps; you should see api, front, and db containers.

8. Automated Backups (Community‑tested Cron) #

Create a backup script /home/revolt/backup.sh:

#!/usr/bin/env bash
TIMESTAMP=$(date +%F_%H-%M)
BACKUP_DIR="/var/backups/revolt"
mkdir -p "$BACKUP_DIR"

# Dump PostgreSQL
docker exec -t revolt-db pg_dump -U revolt -Fc revolt > "$BACKUP_DIR/revolt_$TIMESTAMP.dump"

# Archive uploads (media)
tar -czf "$BACKUP_DIR/uploads_$TIMESTAMP.tar.gz" -C /home/revolt/uploads .

# Optional: upload to remote S3 bucket
# aws s3 cp "$BACKUP_DIR" s3://my-revolt-backups/ --recursive

# Prune older than 30 days
find "$BACKUP_DIR" -type f -mtime +30 -delete
chmod +x /home/revolt/backup.sh
# Add to root's crontab (runs at 02:30 daily)
sudo crontab -e
# ──> 30 2 * * * /home/revolt/backup.sh >> /var/log/revolt_backup.log 2>&1

9. Monitoring & Alerts (Prometheus + Grafana Lite) #

The Reddit community recommended a lightweight Prometheus node‑exporter for early warning on CPU/memory spikes.

docker run -d \
  --name node-exporter \
  --restart unless-stopped \
  -p 9100:9100 \
  --pid="host" \
  --net="host" \
  quay.io/prometheus/node-exporter:latest

Then add a Grafana dashboard (import ID 1860 – “Docker Host Overview”) and set alerts for >80 % CPU or RAM usage.

10. Migration Checklist (From Discord) #

  1. Export – Use Discord’s Server Settings → Overview → Export Server Data (JSON + media zip).
  2. Transform – Run the community‑maintained Python script discord2revolt.py (found in r/selfhosted’s wiki) to convert channel structures and user IDs.
  3. Import – Place the transformed JSON into /home/revolt/import/ and execute docker exec revolt-api npm run import.
  4. Parallel Run – Keep Discord alive for 48 h while users test Revolt; gather feedback via a dedicated “#migration‑feedback” channel.
  5. Cut‑over – Disable invites on Discord, announce the final switch, and archive the old server.

Following this checklist saved ≈30 % of migration time for the most active community (≈1 k members) according to the thread’s author, u/ChronoMason.


SolutionUI FamiliarityVoice SupportFederationBot EcosystemTypical VPS Specs (2026)Ease of Maintenance
Discord (official)★★★★★ (native)★★★★★ (low‑latency)★★★★★ (official API)N/A (cloud)✔ (no ops)
Revolt★★★★☆ (Discord‑like)✖ (text only) – add Jitsi for voice★★★★☆ (Node.js & Python bots)2 vCPU / 4 GB RAM / 50 GB SSD✔ (Docker)
Matrix + Element★★★☆☆ (different UI)★★☆☆ (needs Jitsi/Mumble)★★★★★ (federated)★★★★☆ (many bridges)2 vCPU / 6 GB RAM / 80 GB SSD✖ (Synapse tuning)
Zulip★★☆☆ (threaded)★★☆☆ (limited)1 vCPU / 2 GB RAM / 30 GB SSD✔ (simple)
**Mumble + Rocket