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.