# Self-hosting Run the complete RelayRTC stack with prebuilt Docker images. Run RelayRTC on your own computer using its published container images. This guide starts the API, signaling, media, TURN, console, admin dashboard, PostgreSQL, Prometheus and Grafana. Database migrations run before the application services start. You only need the Docker configuration files and your environment settings. You do not need to clone the source repository or install Node.js, Go or pnpm. ## Requirements - Docker Desktop with Linux containers on Windows or macOS, or Docker Engine with the Compose plugin on Linux. - An AMD64 computer. The current published images target Linux AMD64; native ARM64 images are not included in this release. - GitHub and Google OAuth credentials, plus a Resend API key and verified sender for console authentication and email. Start Docker and check that Compose is available: ```bash docker version docker compose version ``` > **Local setup** > The addresses below are for applications and browsers running on the same computer as Docker. Hosting on a server or connecting from another device requires reachable addresses, firewall rules and HTTPS for browser camera and microphone access. ## Download the configuration Create a folder named `relayrtc`. Download these three files into it: | File | Download | | --- | --- | | `docker-compose.yml` | [Open on GitHub](https://github.com/relayrtc/relayrtc/blob/f07e41d/docker-compose.yml) | | `docker-compose.release.yml` | [Open on GitHub](https://github.com/relayrtc/relayrtc/blob/f07e41d/docker-compose.release.yml) | | `.env.example` | [Open on GitHub](https://github.com/relayrtc/relayrtc/blob/f07e41d/.env.example) | On each GitHub file page, use **Download raw file** in the file toolbar. Save the actual file content, not the GitHub HTML page. Keep the filenames exactly as shown, including the leading dot in `.env.example`. These links point to the configuration used for the `0.1.0` container images. Copy `.env.example` to `.env`. In PowerShell: ```powershell Copy-Item .env.example .env ``` In Windows Command Prompt: ```cmd copy .env.example .env ``` On macOS or Linux: ```bash cp .env.example .env ``` Open `.env` in your editor. Run all remaining commands from this folder. ## Set passwords and secrets Use a separate random value for each setting: | Setting | Used for | | --- | --- | | `POSTGRES_PASSWORD` | PostgreSQL authentication. | | `BETTER_AUTH_SECRET` | Console and dashboard authentication. | | `PARTICIPANT_TOKEN_SIGNING_SECRET` | Signing participant tokens. | | `RELAYRTC_INTERNAL_SECRET` | Authentication between services. | | `TURN_SHARED_SECRET` | Issuing temporary TURN credentials. | | `GRAFANA_ADMIN_PASSWORD` | Grafana administrator login. | You can generate a value through Docker. Run this command once for each setting and paste each result into `.env`: ```bash docker run --rm node:24-alpine node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))" ``` Keep these values separate. The services reject placeholder or shared credentials. Set `DATABASE_URL` using the same PostgreSQL password: ```dotenv DATABASE_URL=postgresql://relaykit:YOUR_POSTGRES_PASSWORD@localhost:5433/relaykit ``` This address is for tools running on your computer. Compose supplies the containers with their internal database address automatically. Generate the webhook encryption key: ```bash docker run --rm node:24-alpine node -e "console.log(require('node:crypto').randomBytes(32).toString('base64'))" ``` Paste the result into `WEBHOOK_SIGNING_ENCRYPTION_KEY`. This setting requires a base64-encoded 32-byte key, not a hexadecimal string. > **Keep your secrets private** > Do not share `.env`, commit it to Git, or put its values in frontend code. Keep a secure backup of the webhook encryption key. Existing webhook signing secrets cannot be decrypted without it. ## Configure local addresses Set these values in `.env`: ```dotenv RELAYRTC_VERSION=0.1.0 API_PORT=8080 SIGNALING_PORT=8081 MEDIA_PORT=8083 CONSOLE_PORT=3002 POSTGRES_PORT=5433 BETTER_AUTH_URL=http://localhost:3001 CONSOLE_AUTH_URL=http://localhost:3002 BETTER_AUTH_TRUSTED_ORIGINS=http://localhost:3001,http://localhost:3002 RELAYRTC_API_URL=http://localhost:8080 RELAYRTC_SIGNALING_ALLOWED_ORIGINS=http://localhost:3005,http://localhost:3002 MEDIA_RTC_LISTEN_IP=0.0.0.0 MEDIA_RTC_ANNOUNCED_ADDRESS=127.0.0.1 MEDIA_RTC_PORT=40000 MEDIA_RTC_MAX_PORT=40003 MEDIA_WORKERS=1 TURN_REALM=relayrtc.local TURN_PUBLIC_IP=127.0.0.1 TURN_DOCKER_RELAY_ADDRESS=172.30.0.11 TURN_STUN_URLS=stun:localhost:3478 TURN_URLS=turn:localhost:3478?transport=udp,turn:localhost:3478?transport=tcp ``` This example allows an application frontend at `http://localhost:3005`. Replace that origin with your application's address, including its port. `localhost` and `127.0.0.1` are different origins. Keep `TURN_DOCKER_RELAY_ADDRESS=172.30.0.11`; it is the TURN container's address in the Docker network. The URLs above use TURN over UDP and TCP. The container generates its own self-signed TLS certificate at startup, but trusted TURN TLS is not configured by this local example. ## Configure sign-in and email Replace these placeholders in `.env` with your provider credentials: - `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET`. - `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET`. - `RESEND_API_KEY` and `RESEND_FROM_EMAIL`. Use a verified Resend sender. The current configuration requires both OAuth providers and the email settings, even if you plan to use email and password sign-in. For the console, register these callback URLs with the respective providers: ```text http://localhost:3002/api/auth/callback/github http://localhost:3002/api/auth/callback/google ``` If you use OAuth on the admin dashboard, its callback URLs use port `3001`. Google supports multiple authorized redirect URIs. GitHub OAuth applications have one configured callback URL; use the provider application that matches the interface you intend to sign into. ## Download and start the images Validate your configuration: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml config --quiet ``` Download the published images: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml pull ``` Start the stack: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml up -d --no-build --wait ``` Docker downloads the images from GitHub Container Registry. No GitHub login is needed for public images. The first download can take several minutes, depending on your connection. The release Compose file selects the published images. Always include both `-f` arguments and `--no-build` when starting this setup; the base Compose file also contains source build definitions. Check the services: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml ps -a ``` Application services should be running and become healthy. The `migrate` container exits after applying the database migrations. Exit code `0` means it completed successfully. ## Open the console Open [localhost:3002](http://localhost:3002), create your account, organization, project and environment, then create a secret API key. | Service | Local address | | --- | --- | | Console | `http://localhost:3002` | | Admin dashboard | `http://localhost:3001` | | REST API | `http://localhost:8080/v1` | | Signaling | `ws://localhost:8081/v1/connect` | | Media readiness | `http://localhost:8083/ready` | | PostgreSQL | `localhost:5433` | | STUN and TURN | `localhost:3478` | | Prometheus | `http://localhost:9090` | | Grafana | `http://localhost:3000` | Grafana uses the administrator username and password from `.env`. Dashboard access follows the application's authorization rules. The media HTTP service is an internal control endpoint, not an SDK endpoint. Browsers receive their media transport configuration through signaling. ## Connect an application Configure your application's backend: ```dotenv RELAYRTC_API_URL=http://localhost:8080/v1 RELAYRTC_SIGNALING_URL=ws://localhost:8081/v1/connect RELAYRTC_SECRET_KEY=your-project-secret-key ``` Follow [Build your first call](/quickstart) to create a room and issue participant tokens. Use the local API and signaling addresses above if the quickstart uses different ports. Keep the secret API key on your backend. Send only the participant token and signaling URL to the frontend. Join the same room from two browser windows using different participant tokens. Allow camera and microphone access, then test audio, video, messages and screen sharing. ## Troubleshooting Read the service logs: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml logs --tail=100 api signaling media coturn console migrate ``` | Problem | Check | | --- | --- | | Docker cannot connect | Start Docker Desktop or Docker Engine. | | A configuration file is missing | Run the command from the folder containing both Compose files and `.env`. | | Image download is denied | Check the image name and version. The GHCR package must be public for anonymous downloads. | | Docker tries to build source | Include the release Compose file and `--no-build`. | | A port is already in use | Stop the other stack or application, or change its host port in `.env`. | | API exits during startup | Replace placeholder secrets and check the webhook key's base64 encoding. | | PostgreSQL rejects the password | An existing volume keeps its original database password. Changing `.env` does not update that password. | | Signaling rejects a connection | Match the frontend origin in `RELAYRTC_SIGNALING_ALLOWED_ORIGINS`. | | Remote media is missing | Check media and TURN addresses, Docker port mappings and the host firewall. | | Camera or microphone is unavailable | Check browser permissions and other applications using the device. | | OAuth or email fails | Check provider credentials, callback URLs and your verified email sender. | See [Troubleshooting calls](/guides/troubleshooting) for browser checks. ## Change settings or upgrade After editing `.env`, recreate the services to apply the settings: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml up -d --no-build --wait ``` To upgrade, back up your database and `.env`, read the release notes, and download any updated configuration files. Set `RELAYRTC_VERSION` to the published version you want to run, then download its images: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml pull ``` Run that version's migrations before starting the updated services: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml run --rm --no-deps migrate ``` The existing PostgreSQL service must be running for this command. Stop if migration fails. After a successful migration: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml up -d --no-build --wait ``` Schedule upgrades when no calls are active. Recreating media or signaling services interrupts calls. Returning to an older image does not undo database migrations. ## Stop or remove the installation Stop the containers while keeping your database and other saved data: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml down ``` To remove the saved data as well: ```bash docker compose -f docker-compose.yml -f docker-compose.release.yml down --volumes ``` > **Removing volumes deletes data** > This removes accounts, projects, API keys, rooms and other stored records. Back up anything you need before running `down --volumes`.