SETUP · 03
The no-CLI route: same result, no subwave binary on your host. Reach for it if you'd rather not run an installer, you're scripting the deploy, or you just like typing the commands yourself. Four steps get you a public single-host deploy: Caddy on the edge, Cloudflare in front, and Icecast, Controller, and Web kept internal.
If a single binary on your host doesn't bother you, the standalone CLI folds these four steps into curl … | sh (which chains init and start behind two Enter prompts) followed by subwave setup. See Quick Start. It pulls the same compose images and writes to the same state/ layout, so you can switch between the two whenever you like.
No clone needed. SUB/WAVE installs from a single docker-compose.yml + a 3-var .env:
mkdir subwave && cd subwave
curl -O https://raw.githubusercontent.com/perminder-klair/subwave/main/docker-compose.yml
curl -O https://raw.githubusercontent.com/perminder-klair/subwave/main/.env.example
mv .env.example .env
$EDITOR .envThree keys boot the stack. The first-run wizard at /onboarding collects the rest once the containers come up.
# .env (repo root) — three keys, that's the whole boot config.
# Admin gate for /admin + the first-run wizard. REQUIRED in prod.
ADMIN_USER=admin
ADMIN_PASS=replace-me-with-a-strong-string # openssl rand -hex 16
# Public origin — used for OG tags, sitemap, share cards.
SITE_URL=https://radio.example.comClone the repo and run ./scripts/setup.sh. It scaffolds the same .env and sets the state-dir permissions. Or run npm run setup for a terminal wizard that does the same thing the browser flow does, no browser needed.
docker compose up -dWhat just started:
state/icecast-secrets.env (no scripts/setup.sh step needed). The entrypoint sources them before it execs liquidsoap. Internal-only.:7700)By default, docker-compose.yml pulls ghcr.io/perminder-klair/subwave-*:latest. To pin a release, set SUBWAVE_VERSION=v1.2.3 in your root .env. To build from a local clone instead, add --build to the up command.
Swap the compose file for docker-compose.byo.yml: same stack minus the bundled Caddy, with web / controller / broadcast bound to :7700 / :7701 / :7702.
You have to front this with a reverse proxy. The web UI calls /api/*, /stream.mp3, and /stream.opussame-origin, and those paths are baked into the image at build time. Without a proxy routing them to the controller and Icecast, the page loads but the player is dead: no metadata, no audio. Here's the route table to replicate (it mirrors docker/Caddyfile):
/stream.mp3 → host:7702 # disable proxy buffering for live audio
/stream.opus → host:7702 # ditto — Ogg-Opus mount served from same Icecast
/api/* → host:7701/* # strip the /api prefix
/* → host:7700 # everything else → webIf you need separate hostnames per surface, rebuild the web image with NEXT_PUBLIC_API_URL and NEXT_PUBLIC_STREAM_URL set; those are baked at build time, not runtime.
open http://localhost:7700/onboardingOr https://your-host/onboarding if you're not on localhost.
Sign in with the ADMIN_USER / ADMIN_PASS you set in .env. The wizard collects each of these, tests them against the live service, and saves them:
state/setup-config.json.state/secrets.env (mode 0600, sourced into process.env on boot).tts-heavysidecar: tick the “Enable Chatterbox + PocketTTS” box in the wizard, then start it with docker compose --profile tts-heavy up -d (or set COMPOSE_PROFILES=tts-heavy in .env so future up -d calls bring it up automatically).npm run setup walks the same flow in the terminal. Same checks, same saved config, same end state. That path needs a git clone and Node 20+.
The repo ships a health probe. It checks the containers, hits /api/health and /api/now-playing, and scans recent logs for errors. Run it after any deploy:
./scripts/health-check.shAuto-detects which compose file is live and which host port Caddy is mapped to. Exits 0 if healthy. Safe to wire into cron or a status page.
npm startopens the operator console: a menu for stack status, a diagnostic sweep, logs, restart, and the terminal player. It's how you'll run the station day to day once it's installed.
WHAT'S NEXT
The stack is on the air. When a new version lands, head to Updates & Help for the rebuild-only-what-changed workflow and a troubleshooting checklist.