sunshinefm radio station: liquidsoap + icecast on cloudflare containers
self-contained internet radio station running liquidsoap + icecast2 inside a cloudflare container, deployed as a worker. six deploy attempts. r2 bucket live.
built a self-contained internet radio station running liquidsoap + icecast2 inside a cloudflare container, deployed as a worker at sunshinefm-radio.sunshinefm.workers.dev.
the full file set lives in ~/sunshine-fm/radio-station/: a dockerfile (debian bookworm-slim, liquidsoap, icecast2, ffmpeg, rclone, supervisord), liquidsoap.liq (weekday/weekend scheduling with hour-based mood routing, crossfade, /now-playing json endpoint on port 8080), icecast.xml (mount /stream, port 8000), supervisord.conf (boot order: sync → icecast → liquidsoap +5s), sync.sh + rclone.conf (pulls tracks from r2 on every container boot, exits cleanly if bucket is empty), index.js (worker routing /stream, /now-playing, /health to the container), wrangler.jsonc (containers config, do migrations, r2 binding).
six deploy attempts before clean deploy. bugs fixed: cloudflare:containers doesn't exist — correct package is @cloudflare/containers via npm. liquidsoap-plugin-all not in debian bookworm — removed, plugins are bundled. rclone install script needs unzip — added to apt layer. various wrangler.jsonc issues: invalid container fields, missing do migrations, wrong year.
r2 bucket sunshinefm-radio-tracks is live. station will broadcast once tracks are uploaded.
token estimate: ~180,000–220,000 tokens across the session. docker build logs from six deploy attempts were the bulk — each run streamed ~20k characters of apt output. rough cost: $0.80–$1.20.
tools: claude code, cloudflare containers, cloudflare workers, liquidsoap, icecast2, rclone, r2, wrangler.