AttendiBotAttendiBot

Deployment

Production deployment with Docker, Dokploy, and environment variables.

Self-hosting preview — Managed AttendiBot hosting is the recommended path today. Self-hosting support is coming soon; this guide is published for early adopters and operators preparing their infrastructure.

Production deployment guide for AttendiBot. The system consists of three components: Rust backend (bot + API), PostgreSQL, and Next.js web (BFF + dashboard).

Architecture overview

Loading diagram…

Key principle: The Rust API on port 8080 should be reachable from the web BFF only — not exposed publicly. Auth.js routes (/api/auth/*) must stay on the Next.js app.


Prerequisites

  • Docker (recommended) or bare-metal with Rust + Node.js
  • PostgreSQL 18+
  • Discord application configured — see Discord Setup
  • Domain with HTTPS for the web app

Backend deployment

Build and run from backend/:

cd backend
docker compose up --build

The Dockerfile uses cargo-chef with BuildKit cache mounts for faster rebuilds.

Production environment variables

VariableRequiredDescription
DISCORD_TOKENYesDiscord bot token
ENVIRONMENTYesSet to production
DATABASE_URLYesPostgreSQL connection string
WEBHOOK_SECRETYesMust not be default placeholder
API_INTERNAL_SECRETYesMust not be default placeholder
HTTP_PORTNoDefault 8080
RUST_LOGNoe.g. info,attendibot_bot=debug
BOT_ACTIVITY_TEXTNoBot presence string

Production rejects default placeholders for WEBHOOK_SECRET and API_INTERNAL_SECRET.

Dokploy notes

  • Keep Clean Cache disabled for normal deploys (preserves Docker layer and BuildKit caches)
  • Enable Clean Cache only when debugging stale build artifacts
  • Typical build times: 1–2 min (source change), 3–4 min (cold or dependency change)

Health check

curl http://localhost:8080/health

Expected: {"status":"ok"} (when database is connected)


Web deployment

Docker / Dokploy

Build from the attendibot-web repo root (Fumadocs MDX in content/docs/ is compiled at build time):

docker build -t attendibot-web .

When working from the AttendiBot monorepo checkout, regenerate MDX from markdown before building:

cd web && npm run sync-docs

Dokploy should use the web repository with build context . (repo root) and Dockerfile at the repository root.

Runtime environment variables:

VariableDescription
AUTH_SECRETAuth.js encryption secret
AUTH_DISCORD_IDDiscord OAuth client ID
AUTH_DISCORD_SECRETDiscord OAuth client secret
ATTENDIBOT_API_BASE_URLInternal backend URL (see below)
ATTENDIBOT_API_INTERNAL_SECRETMust match backend API_INTERNAL_SECRET
NEXT_PUBLIC_SITE_URLPublic site URL (HTTPS)
STRIPE_SECRET_KEYStripe secret key for Checkout and webhooks
STRIPE_WEBHOOK_SECRETStripe webhook signing secret
STRIPE_PRICE_PRO_MONTHLYStripe Price ID for Pro monthly
STRIPE_PRICE_PRO_ANNUALStripe Price ID for Pro annual
STRIPE_PRICE_ENTERPRISE_MONTHLYStripe Price ID for Enterprise monthly
STRIPE_PRICE_ENTERPRISE_ANNUALStripe Price ID for Enterprise annual

See billing setup for Stripe Dashboard configuration.

Build args (Docker):

VariableDescription
NEXT_PUBLIC_DISCORD_INVITE_URLFull bot invite URL
NEXT_PUBLIC_DISCORD_CLIENT_IDDiscord app client ID

Web → backend connectivity

Set on the web service:

ATTENDIBOT_API_BASE_URL=http://attendibot-backend-xxx:8080
ATTENDIBOT_API_INTERNAL_SECRET=<same as backend>

Use the backend container's internal Docker hostname, not the public site URL.

Verify from the web container:

node -e "console.log(process.env.ATTENDIBOT_API_BASE_URL)"
node -e "fetch(process.env.ATTENDIBOT_API_BASE_URL+'/health').then(r=>r.text()).then(console.log)"

Vercel

Deploy web/ to Vercel. Set the same environment variables. Point ATTENDIBOT_API_BASE_URL to your backend's reachable URL (ensure network access from Vercel to your backend).

Invite URL after deploy

For "Add to Discord" to work, set at least one of:

  • Runtime: AUTH_DISCORD_ID or DISCORD_INVITE_URL
  • Build time: NEXT_PUBLIC_DISCORD_INVITE_URL or NEXT_PUBLIC_DISCORD_CLIENT_ID

Verify: view page source, search for oauth2/authorize, confirm client_id= is present.


Database

PostgreSQL stores all session records, leaderboard data, signing keys, and configuration.

Migrations

Migrations run automatically when the backend starts (sqlx::migrate!).

Migration files in backend/migrations/:

MigrationPurpose
001Initial schema
002Voice tracking tables
003Log destinations
004Drop legacy guild configs
005Reset anchor modes
006Competitive features (fairness, subscriptions, webhooks, verified roles)

Backups

Back up PostgreSQL regularly. Signing keys (encrypted) and all session records live in the database.


Post-deploy checklist

After deployment:

  1. Backend health check passes (/health)
  2. Web can reach backend (verify from web container)
  3. Discord OAuth redirect URI matches production URL
  4. "Add to Discord" button works
  5. Sign in to dashboard succeeds
  6. Generate and unlock signing keys
  7. Configure tracking and test a voice session
  8. Verify a session on the public verifier

See also docs/marketing/post-deploy-checklist.md for SEO and bot directory submission.


Network security

RuleReason
Do not expose /api/v1 publiclyRequires BFF JWT; bypass breaks auth model
Keep /api/auth/* on Next.jsAuth.js handles OAuth callbacks
Use strong secrets for API_INTERNAL_SECRET and WEBHOOK_SECRETPrevents unauthorized API access
HTTPS on web appRequired for Discord OAuth

Edit on GitHub

On this page