OpenCall

Run locally with Docker

One command brings up Postgres, storage and LiveKit on your machine — the only thing left to fill in by hand is Discord.

Running locally is the fastest way to see OpenCall working: nothing is provisioned in the cloud, nothing costs anything, and you can break whatever you want. It is also the setup to use if you intend to change the code.

docker compose brings up the three pieces of infrastructure the app depends on — Postgres, MinIO (S3-compatible, standing in for Cloudflare R2) and a LiveKit server (standing in for LiveKit Cloud). The app itself, Next.js, runs on your machine with pnpm dev, outside the containers, so hot reload keeps working while you edit.

Discord is the one thing that stays manual

Login goes through Discord's servers, so it cannot be containerized: you need a Discord application of your own, with http://localhost:3000 registered as the redirect. It is step 2 below and takes a couple of minutes.

What you need

  • Docker Desktop running — docker.com/get-started. On Windows it asks to enable WSL 2 during install; accept it.

  • Node.js, which is what provides npm — see "Before you start" in Requirements.

  • pnpm, the package manager the repo uses:

    npm install -g pnpm
  • A fork of the repository, from GitHub repository.

1. Clone your fork

Replace YOUR-USERNAME with your GitHub username.

git clone https://github.com/YOUR-USERNAME/OpenCall.git
cd OpenCall

Then install the dependencies:

pnpm install

2. Create the Discord application

Follow Set up Discord, with one difference: the Redirect URI is the local address, not a domain.

http://localhost:3000/api/auth/callback/discord

Keep the Client ID and the Client Secret at hand — they go into the next step.

3. Fill in the .env

The repo ships a .env.docker.example whose values already match docker-compose.yml. Copy it:

cp .env.docker.example .env

Open the .env and fill in the only two empty lines that matter:

DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=

Everything else — database, LiveKit, MinIO — is already pointing at the containers, and NEXTAUTH_SECRET comes with a development value that is fine locally.

It has to be .env, not .env.local

Next.js reads both, but the Prisma CLI only reads .env. If the file has the other name, pnpm dev works and the migration fails with Environment variable not found: DATABASE_URL.

4. Bring it up

With Docker Desktop open:

pnpm dev:docker

That single command does three things in order: brings up the containers (pnpm docker:up), creates the tables in Postgres (prisma migrate dev) and starts Next.js (pnpm dev). When it finishes it prints the address:

http://localhost:3000

minio-init exiting is not an error

Among the containers there is a one-shot job that creates the bucket and makes it publicly readable. It runs once and stops — exited (0) in Docker Desktop is what success looks like for it.

5. First login

Open localhost:3000 and log in with Discord.

The first account to log in while the database is empty is created as ADMIN, and a text channel and a voice channel named Geral are created with it. Since this is your machine, that first account is yours.

Day to day

CommandWhat it does
pnpm dev:dockerInfrastructure + migrations + app, all at once
pnpm devOnly the app, when the containers are already up
pnpm docker:upOnly the containers
pnpm docker:downStops the containers, keeps the data
docker compose down -vStops and wipes the database and the uploaded files

What is listening where

PieceAddressCredentials
App (Next.js)http://localhost:3000—
Postgreslocalhost:5433opencall / opencall, database opencall
MinIO (S3 API)http://localhost:9000opencall / opencall123
MinIO (web console)http://localhost:9001same as above
LiveKitws://localhost:7880devkey / secret

Postgres is on 5433, not the usual 5432, on purpose: it avoids clashing with a Postgres you may already have installed on the machine.

Limits of the local setup

  • Voice and video only work on this machine. The LiveKit container announces 127.0.0.1 as its ICE candidate, so another device on the same Wi-Fi opens the page but never connects to a call. To test with other people, use the Demo deploy (Render).
  • This is not the production deploy. The docker-compose.yml is development infrastructure with fixed keys and passwords in plain sight. What goes to production is the Dockerfile at the root of the repo, built by Railway or Render — see Production deploy (Railway).
  • GIFs in chat need a key. GIPHY_API_KEY is empty in the example file; without it the GIF button simply does not show up and the rest of the chat works the same.

When something goes wrong

SymptomCause
Cannot connect to the Docker daemonDocker Desktop is not running
port is already allocatedSomething else is on 3000, 9000 or 7880 — close it and try again
Environment variable not found: DATABASE_URLThe file is named .env.local; it has to be .env
Login returns invalid_redirect_uriThe Redirect URI in Discord does not match http://localhost:3000/api/auth/callback/discord exactly
Chat images fail to uploadThe minio-init job did not run — pnpm docker:down and pnpm docker:up again

Next step

To put an instance on the air for other people, without a card: Demo deploy (Render).

On this page