addaInstall

Self-hosting

Production deployment: configuration, HTTPS, custom proxies, persistence and scaling.

adda runs on one server (2 vCPU and 4 GB is a fine start for a small community). You host one thing, the stack: backend, web app, streaming server, Postgres and Redis. Nothing of ours is in the path.

The easy path

scripts/install.sh does everything below: it generates the secrets, starts the stack and gets HTTPS through the bundled Caddy. Follow these steps only for a custom setup (an existing reverse proxy, an external Postgres, separate hostnames).

1. Configure

git clone https://github.com/shahadathhs/adda.git
cd adda
cp .env.example .env

At minimum set these in .env. The full list is in Configuration.

JWT_SECRET=$(openssl rand -hex 48)
POSTGRES_PASSWORD=$(openssl rand -hex 16)

ADDA_DOMAIN=example.com
CORS_ORIGINS=https://example.com

SUPERADMIN_EMAIL=you@example.com
SUPERADMIN_PASSWORD=$(openssl rand -base64 18)
SEED_TEST_USERS=false

# Public URLs (one domain; playback is proxied under /hls)
HLS_BASE_URL=https://example.com/hls
NEXT_PUBLIC_API_BASE_URL=https://example.com
NEXT_PUBLIC_HLS_BASE_URL=https://example.com/hls
PASSWORD_RESET_URL=https://example.com/reset-password

Optionally add the SMTP_* values for emailed reset links and live emails.

2. Start

docker compose --profile prod up -d --build

The backend applies database migrations when it starts, and waits for Postgres and Redis. Caddy serves traffic once the stack is healthy.

3. A different reverse proxy

The bundled Caddy routes /api, /ws, /health and /hls to the right services and everything else to the web app (see infra/caddy/Caddyfile). If you proxy yourself, keep that routing, and make sure /ws keeps the upgrade headers:

location /ws {
    proxy_pass http://127.0.0.1:7001;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 3600s;
}

Do not publish /metrics. Keep port 1935 open to the internet for RTMP; mediamtx checks every publisher against the channel's key.

4. What to keep

DataWhere it lives
Accounts, channels, chat, pollsPostgres (the postgres_data volume)
Recordings./recordings/
Emotes, banners, pictures and videos./uploads/
Presence, rate limits, live talliesRedis, ephemeral by design

Back up the database, uploads/ and recordings/. Everything else rebuilds.

5. Upgrading

git pull
docker compose --profile prod up -d --build

Migrations run automatically. Take a backup first.

Scaling notes

  • The backend keeps no per-request state, and WebSocket fan-out goes through Redis, so several backend instances behind one Redis work (this is tested with two real processes). Use sticky sessions for /ws.
  • Streaming is passthrough: mediamtx remuxes RTMP to HLS at the source bitrate. Size your upload bandwidth for viewers times bitrate, or put a CDN in front of /hls.

Ports

ServicePortPurposePublished
Caddy80, 443HTTPS entrypointinternet (prod profile)
mediamtx RTMP1935Encoder ingestinternet
Web5173Web app (SSR)localhost
Backend7001REST and WebSocketlocalhost
mediamtx HLS8888Playbacklocalhost (Caddy proxies it)
mediamtx API9997Controllocalhost
Postgres5432localhost
Redis6379localhost