Skip to content

Self-Hosting

import { Steps } from ‘@astrojs/starlight/components’;

br\u016bhi Cloud is packaged as a single Docker image containing all services. Docker Compose is the recommended deployment method.

The quickest way to install brūhi Cloud on a Linux server is using the automated interactive script from the official bruhi-deploy repository:

Terminal window
bash <(curl -fsSL https://raw.githubusercontent.com/bruhi-technologies/bruhi-deploy/main/install.sh)

The script checks Docker prerequisites, prompts for your domain and port, auto-generates secure passwords, configures .env, and pulls the container image.


  1. Download Deployment Files

    Create an installation folder and fetch the compose definitions:

    Terminal window
    mkdir -p ~/bruhi-cloud && cd ~/bruhi-cloud
    curl -fsSL https://raw.githubusercontent.com/bruhi-technologies/bruhi-deploy/main/docker-compose.yml -o docker-compose.yml
    curl -fsSL https://raw.githubusercontent.com/bruhi-technologies/bruhi-deploy/main/Caddyfile -o Caddyfile
    curl -fsSL https://raw.githubusercontent.com/bruhi-technologies/bruhi-deploy/main/.env.example -o .env
  2. Configure Environment Variables

    Edit .env and configure your domain and credentials:

    # Activate bundled Icecast and Caddy HTTPS reverse proxy
    COMPOSE_PROFILES=bundled-icecast,proxy
    # Your domain name (required for automatic SSL certificates and Passkeys)
    DOMAIN=radio.yourdomain.com
    BRUHI_URL=https://radio.yourdomain.com
    BRUHI_RP_ID=radio.yourdomain.com
    # Streaming security passwords
    ICECAST_SOURCE_PASSWORD=your_secure_source_password
    ICECAST_ADMIN_PASSWORD=your_secure_admin_password
    ICECAST_RELAY_PASSWORD=your_secure_relay_password
  3. Start the Stack

    Terminal window
    docker compose up -d
  4. Verify Health

    Terminal window
    curl http://localhost:8000/healthz
    # {"status":"ok"}
VariableDefaultDescription
PORT8000API server & web dashboard host port
LOG_LEVELwarningLog verbosity (debug, info, warning, error)
BRUHI_ENVproductionEnvironment mode (development or production)
BRUHI_URL—Base public URL used for passkeys, reset links, etc.
DOMAIN—Domain name for Caddy automatic HTTPS
COMPOSE_PROFILESbundled-icecast,proxyActive Compose profiles (bundled-icecast, proxy)
BRUHI_ICECAST_MODEbundledbundled (internal container) or external
ICECAST_HOST_PORT8010Host port mapped to bundled Icecast
ICECAST_SOURCE_PASSWORD—Source connection password for Icecast (Required in prod)
ICECAST_ADMIN_PASSWORD—Admin web UI password for Icecast (Required in prod)
ICECAST_RELAY_PASSWORD—Relay password for Icecast (Required in prod)
ICECAST_MAX_CLIENTS500Maximum concurrent listener connections on Icecast
ICECAST_MAX_SOURCES20Maximum concurrent streaming sources
BRUHI_AUDIO_API_TOKENauto-generatedInternal communication token for Rust audio engine
BRUHI_DB/app/data/bruhi.dbPath to consolidated SQLite database inside container
AUDIO_DIR/app/audio_filesPath to uploaded audio files & recordings
BRUHI_RP_ID—WebAuthn / Passkeys Relying Party ID (hostname only)
BRUHI_RP_NAMEbrūhi CloudWebAuthn / Passkeys application display name
BRUHI_ADMIN_EMAIL—Optional initial admin/owner email for pre-seeding
BRUHI_ADMIN_PASSWORD—Optional initial admin/owner password for pre-seeding
CORS_ORIGINS''Space-separated allowed CORS origins

Docker Compose Definition (docker-compose.yml)

Section titled “Docker Compose Definition (docker-compose.yml)”

The production deployment uses docker-compose.yml:

services:
icecast:
profiles: ["bundled-icecast"]
image: libretime/icecast:2.5.0-alpine
container_name: bruhi-icecast
ports:
- "${ICECAST_HOST_PORT:-8010}:8000"
environment:
ICECAST_SOURCE_PASSWORD: "${ICECAST_SOURCE_PASSWORD:?Required}"
ICECAST_ADMIN_PASSWORD: "${ICECAST_ADMIN_PASSWORD:?Required}"
ICECAST_RELAY_PASSWORD: "${ICECAST_RELAY_PASSWORD:?Required}"
ICECAST_HOSTNAME: "${ICECAST_HOSTNAME:-localhost}"
ICECAST_MAX_CLIENTS: "${ICECAST_MAX_CLIENTS:-500}"
ICECAST_MAX_SOURCES: "${ICECAST_MAX_SOURCES:-20}"
restart: always
bruhi-cloud:
image: "${IMAGE:-ghcr.io/bruhi-technologies/bruhi-cloud:latest}"
container_name: bruhi-cloud
depends_on:
icecast:
condition: service_started
required: false
ports:
- "${PORT:-8000}:8000"
volumes:
- bruhi_audio:/app/audio_files
- bruhi_playlists:/tmp/liquidsoap-playlists
- bruhi_db:/app/data
- bruhi_audio_sockets:/tmp/bruhi-audio
environment:
PORT: "${PORT:-8000}"
LOG_LEVEL: "${LOG_LEVEL:-warning}"
BRUHI_ENV: "production"
SESSION_COOKIE_SECURE: "true"
CORS_ORIGINS: "${CORS_ORIGINS:-}"
ICECAST_SOURCE_PASSWORD: "${ICECAST_SOURCE_PASSWORD:-${ICECAST_PASSWORD:-}}"
BRUHI_AUDIO_API_TOKEN: "${BRUHI_AUDIO_API_TOKEN:-}"
BRUHI_ICECAST_MODE: "${BRUHI_ICECAST_MODE:-bundled}"
BRUHI_URL: "${BRUHI_URL}"
BRUHI_RP_ID: "${BRUHI_RP_ID}"
BRUHI_RP_NAME: "${BRUHI_RP_NAME:-brūhi Cloud}"
BRUHI_DB: "/app/data/bruhi.db"
AUDIO_DIR: "/app/audio_files"
BRUHI_AUDIO_API: "http://localhost:7700"
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/healthz"]
interval: 60s
timeout: 10s
retries: 3
caddy:
profiles: ["proxy"]
image: caddy:2.8-alpine
container_name: bruhi-caddy
depends_on:
- bruhi-cloud
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
environment:
DOMAIN: "${DOMAIN:-localhost}"
restart: always
volumes:
bruhi_audio:
bruhi_playlists:
bruhi_db:
bruhi_audio_sockets:
caddy_data:
caddy_config:
VolumeMount pathContents
bruhi_audio/app/audio_filesUploaded audio files and broadcast recordings
bruhi_db/app/dataConsolidated SQLite database (bruhi.db)
bruhi_audio_sockets/tmp/bruhi-audioShared Unix IPC sockets between API and audio engine
caddy_data/dataTLS certificates provisioned by Caddy

brūhi Cloud provides a zero-config reverse proxy setup powered by Caddy. When enabled, Caddy automatically obtains and renews free SSL certificates via Let’s Encrypt.

  1. Set COMPOSE_PROFILES=bundled-icecast,proxy in your .env file.
  2. Set DOMAIN=radio.yourdomain.com in your .env file.
  3. Ensure DNS A/AAAA records for radio.yourdomain.com point to your server’s public IP.
  4. Run docker compose up -d.

If you operate an existing external Nginx proxy:

server {
listen 443 ssl;
server_name radio.yourdomain.com;
ssl_certificate /etc/ssl/bruhi.crt;
ssl_certificate_key /etc/ssl/bruhi.key;
location / {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}

The Upgrade and Connection headers are required for WebSockets (used for WebRTC signaling, playout clock sync, and real-time station telemetry).

Before exposing brūhi Cloud to the internet:

  • Enable HTTPS via bundled Caddy (COMPOSE_PROFILES=bundled-icecast,proxy) or external reverse proxy
  • Set BRUHI_RP_ID (domain name) and BRUHI_URL (https://...)
  • Set strong secrets for ICECAST_SOURCE_PASSWORD and ICECAST_ADMIN_PASSWORD
  • Configure firewall rules: allow ports 80, 443 (HTTPS), 8010 (Icecast), 8100+ (harbors)
  • Schedule regular volume backups for bruhi_db and bruhi_audio
  • Review the Operations & Maintenance Guide for update and backup procedures

For day-to-day operations, updates, password resets, and maintenance CLI commands, see the dedicated Operations & Maintenance Guide.

ProviderServiceStatus
AWSEC2, Lightsail, ECS, EKS✅ Verified
Google CloudCompute Engine, GKE✅ Verified
DigitalOceanDroplets, Kubernetes✅ Verified
HetznerCloud, Dedicated✅ Community tested
Linode / AkamaiCompute Instances✅ Verified