# VPS bundle: Icecast + streamer + Caddy (HTTPS). # # Layout on the VPS (e.g. /opt/airstudio): # docker-compose.yml this file # .env secrets/config (from .env.vps.example) # icecast.xml icecast config (passwords from env via sed at first boot, see DEPLOY.md) # Caddyfile TLS termination # web/ai-radio/ shipped mp3s + playlist.m3u8 + titles.json (shipper target) # # The streamer container reads web/ai-radio/ and feeds icecast; the # generator machine rsync/scps into web/ai-radio/ over SSH. services: icecast: image: icecastofficial/icecast:latest container_name: icecast restart: unless-stopped expose: - "8000" ports: - "8000:8000" # plain HTTP for old stereos (optional; remove to force HTTPS) volumes: - ./icecast.xml:/etc/icecast.xml:ro - ./web:/usr/local/share/icecast/web - icecast-logs:/usr/local/share/icecast/logs streamer: build: context: . dockerfile: Dockerfile.streamer container_name: radio-streamer restart: unless-stopped depends_on: - icecast environment: STREAM_WEBROOT: /usr/local/share/icecast/web/ai-radio ICECAST_ADDR: icecast:8000 ICECAST_SOURCE_PASSWORD: ${ICECAST_SOURCE_PASSWORD} ICECAST_MOUNT: ${ICECAST_MOUNT:-/ai-radio.mp3} STATION_NAME: ${STATION_NAME:-AI Radio} STATION_DESCRIPTION: ${STATION_DESCRIPTION:-Endless AI-generated radio} MP3_BITRATE: ${MP3_BITRATE:-128} STREAM_PUBLIC_URL: ${STREAM_PUBLIC_URL:-https://radio.example.com/ai-radio.mp3} MQTT_ADDR: ${MQTT_ADDR:-} MQTT_USER: ${MQTT_USER:-} MQTT_PASS: ${MQTT_PASS:-} MQTT_TOPIC: ${MQTT_TOPIC:-airstudio/nowplaying} volumes: - ./web:/usr/local/share/icecast/web:ro caddy: image: caddy:2 container_name: caddy restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy-data:/data - caddy-config:/config volumes: icecast-logs: caddy-data: caddy-config: