Quick start guide

Get a Rumo instance running, then configure it to look and speak the way you want.

Docker (recommended)

On Ubuntu or Debian without Docker installed, the script offers to install it for you. Elsewhere, install Docker first.

git clone https://github.com/BrahmjotSingh0/rumo.git
cd rumo
./install.sh      # Windows: .\install.ps1

The script generates .env with randomly generated secrets for whatever isn't already set, asks for an optional domain name, then runs docker compose up -d --build. Running it again later is safe: it reuses whatever secrets and settings you already have instead of overwriting them.

Frontend on http://localhost:5173, backend on http://localhost:5000. The Postgres schema is applied automatically on first run. Open /admin and enter the admin token the script printed (also saved in .env as ADMIN_SETUP_TOKEN) to set your logo, name, tagline, and accent color.

Custom domain and HTTPS: give the installer a domain (with its DNS A record already pointing at this server) and it starts a Caddy reverse proxy that gets you a free, auto-renewing certificate. No manual certbot or nginx config.
./install.sh --domain meet.example.com --yes
This also switches the frontend and backend to be reachable only through Caddy rather than directly over plain HTTP. Re-running the installer later without --domain keeps whatever domain you already configured.

Manual setup (without Docker)

Requires Node.js 22+ and PostgreSQL.

# 1. Create the database and load the schema
createdb rumo
psql rumo < backend/database/schema.sql

# 2. Backend
cd backend
cp .env.example .env   # fill in DB credentials
npm install
npm run dev             # http://localhost:5000

# 3. Frontend (new terminal)
cd frontend
cp .env.example .env
npm install
npm run dev             # http://localhost:5173

See the backend and frontend READMEs for the full environment variable reference and project layout.

HTTPS requirement: camera/microphone access requires HTTPS in the browser (Chrome and Firefox both block getUserMedia on plain HTTP), except on localhost. For a real deployment, put a reverse proxy (Caddy, nginx, Cloudflare Tunnel, etc.) with a TLS certificate in front of frontend/backend, and point CORS_ORIGIN, VITE_API_URL, and VITE_SOCKET_URL at the public HTTPS URLs.

Branding

Open /admin, enter your ADMIN_SETUP_TOKEN, and set the app name, tagline, description, logo, and accent color from a form. It saves to the database and applies immediately, no rebuild or restart.

Prefer a file instead (or never set an admin token)? Edit frontend/public/branding.json:

{
  "appName": "Rumo",
  "tagline": "Connect, collaborate, create.",
  "description": "Free, self-hosted video meetings.",
  "logoIcon": "/brand/icon.svg",
  "logoFull": "/brand/logo.svg",
  "primaryColor": "#2E5BFF"
}

This file is fetched at runtime too (edit it, or bind-mount your own version over it in Docker), and acts as the fallback for anything not set through the admin panel. primaryColor drives a full 50-900 Tailwind shade scale computed on load, so buttons, badges, and focus rings across the landing and pre-join screens follow it automatically. Logo files live in frontend/public/brand/ by default; replace them, update the paths above, or just upload one from /admin.

Scope note: the accent-color retheming covers the landing and pre-join screens. The in-call meeting UI is a large, separate surface that still uses fixed colors, aside from its own existing light/dark toggle in the in-call settings panel.

Languages

UI strings live in frontend/src/i18n/lang.json: one file, each string keyed by language code.

"common.joinMeeting": { "en": "Join Meeting", "es": "Unirse a la reunión" }

To add a language, add its code and label to languages, then add that code to every entry under strings. The language switcher on the home screen picks it up automatically. Currently ships with English and Spanish covering the landing and pre-join screens.

TURN server (optional)

STUN (included, free, via Google's public servers) is enough for most networks. If some participants are behind restrictive NATs/firewalls and can't connect, run your own TURN server (e.g. coturn) and set TURN_SERVERS (backend) plus VITE_TURN_URL, VITE_TURN_USERNAME, VITE_TURN_CREDENTIAL (frontend).

Security notes

SQLAll queries are parameterized (pg placeholders); no string-built queries.
Rate limitingOn by default for the REST API (RATE_LIMIT_* env vars).
Headershelmet sets standard security headers. Content-Security-Policy is off by default since a strict one is easy to break with WebRTC/media/websocket connections.
SessionsNone. No cookies, no accounts, so CORS_CREDENTIALS defaults to false.
Admin panel/admin and /api/settings/* writes require ADMIN_SETUP_TOKEN, checked with a timing-safe comparison. Unset it to disable branding changes entirely.
TLSHandled by the optional Caddy reverse proxy (./install.sh --domain ...), or your own proxy in front for other setups.
Secrets.env/.env.production are gitignored everywhere in the repo. Never commit real credentials.

Host status has no cryptographic backing: whoever creates a room, or is first to join it, becomes host for that session. This is the same trust model as most link-based meeting tools (anyone with the link can join).