A self-hostable Discord moderation bot with an accompanying web dashboard. The bot is written in Rust (Serenity + Poise) and serves its own HTTP API via Axum. The dashboard is a Next.js app that talks to the bot's API and the database directly.
- One Rust binary that can run the gateway bot, the web server, or both, controlled by
RUN_BOT/RUN_WEBenv flags. - Horizontally shardable (
SHARD_INDEX/TOTAL_SHARDS): each shard runs as its own container sharing Postgres and Redis state. - Background/cron jobs use distributed Redis locks so multiple instances never double-execute.
- Production traffic is served behind a Cloudflare Tunnel, which means no inbound ports on the host.
- Backend of frontend (Next.js Server Actions) can interact with Redis for invalidation and Postgres for storing config
Moderation & safety: automod, bad-word rulesets, raid detection, warnings, moderation actions, media-only channels, verification (Turnstile/hCaptcha), reporting, message logging, invite tracking.
Community: leveling (+ rewards/multipliers), starboard, giveaways, birthdays, reaction roles, custom commands, reminders, member counters, join/leave messages, temp voice hubs, tickets, live feed, search integrations (Spotify, YouTube, Genius, GIPHY, TMDB, RAWG), and music playback (Songbird).
Each feature lives in its own vertical slice under src/features/. see
CONVENTIONS.md.
- Rust 1.85+ (edition 2024)
- Node.js 24+ (Corepack comes bundled, for pnpm)
- Docker (for Postgres + Redis)
-
Copy the env template and fill it in:
cp .env.example .env
At minimum, you need
DISCORD_TOKEN,DATABASE_URL,REDIS_URL,POSTGRES_PASSWORD, andREDIS_PASSWORD. -
Start the local databases:
docker compose -f docker-compose.dev.yml up -d
-
Run the bot (migrations run automatically on startup; SQLx uses offline query metadata from
.sqlx/, so no live DB is needed to compile):cargo run
-
In another terminal, run the dashboard:
cd dashboard corepack enable pnpm install pnpm run dev
corepack enableis a one-time setup per machine (it ships with Node.js); it hands out the pnpm version pinned inpackage.json. Install withSHARP_IGNORE_GLOBAL_LIBVIPS=1 pnpm installif your machine ships its own libvips, otherwise sharp's install script tries (and fails) to compile from source.Open http://localhost:3000. The dashboard expects the bot's API at the URL set in
NEXT_PUBLIC_BACKEND_URL.
| Command | What it does |
|---|---|
cargo build --release |
Build the bot |
cargo clippy |
Lint (pedantic/nursery lints are enabled) |
cargo fmt |
Format (config in rustfmt.toml) |
pnpm run lint (in dashboard/) |
Lint the dashboard |
pnpm test (in dashboard/) |
Run Vitest tests |
The full stack lives in docker-compose.prod.yml: two bot shards, a web/API-only container, the
dashboard, Postgres, Redis, and a cloudflared tunnel. One-time setup steps are documented in
comments at the top of that file; then deploy with:
docker compose -f docker-compose.prod.yml up -d --buildFor running many guilds across multiple hosts, see docker-compose.multi.yml.
See .env.example for the full list. Highlights:
| Variable | Purpose |
|---|---|
DATABASE_URL / REDIS_URL |
Postgres and Redis connections |
DISCORD_TOKEN |
Bot token |
RUN_BOT / RUN_WEB / RUN_MIGRATIONS |
Toggle which parts of the binary run |
SHARD_INDEX / TOTAL_SHARDS |
Gateway sharding |
DOMAIN / NEXT_PUBLIC_BACKEND_URL |
Public URLs for links and API calls |
| Third-party keys | Spotify, Google Cloud, Genius, GIPHY, Klipy, TMDB, RAWG |
| Captcha secrets | Turnstile / HCaptcha for the verification feature |
Before writing code, read CONVENTIONS.md (Rust bot) and
dashboard/CONVENTIONS.md (frontend). The short version: keep code
inside the feature it belongs to, share only when 3+ features need it, never use mod.rs, and use
compile-checked SQLx macros.