#+TITLE: Asteroid Radio - Docker Streaming Setup #+AUTHOR: Asteroid Radio Development Team #+DATE: 2025-10-26 * Docker Streaming Overview This guide covers the complete Docker-based streaming setup for Asteroid Radio using Icecast2 and Liquidsoap containers. This approach provides a containerized, portable streaming infrastructure that's easy to deploy and maintain. * Architecture ** Container Stack - *Icecast2 Container*: Streaming server handling client connections - *Liquidsoap Container*: Audio processing and stream generation - *Shared Volumes*: Music library and configuration sharing ** Stream Formats - *High Quality MP3*: 128kbps MP3 stream at /asteroid.mp3 - *High Quality AAC*: 96kbps AAC stream at /asteroid.aac (better efficiency than MP3) - *Low Quality MP3*: 64kbps MP3 stream at /asteroid-low.mp3 (compatibility) ** Network Configuration - *Icecast2*: Port 8000 (streaming and admin) - *Liquidsoap Telnet*: Port 1234 (remote control) - *Internal Network*: Container-to-container communication * Quick Start ** Prerequisites #+BEGIN_SRC bash # Install Docker and Docker Compose sudo apt update sudo apt install docker.io docker compose sudo usermod -a -G docker $USER # Log out and back in for group changes #+END_SRC ** One-Command Setup #+BEGIN_SRC bash # Clone and start git clone https://github.com/fade/asteroid asteroid-radio cd asteroid-radio/docker docker compose up -d #+END_SRC ** Verify Setup #+BEGIN_SRC bash # Check container status docker compose ps # Test streaming (all three formats) curl -I http://localhost:8000/asteroid.mp3 # 128kbps MP3 curl -I http://localhost:8000/asteroid.aac # 96kbps AAC curl -I http://localhost:8000/asteroid-low.mp3 # 64kbps MP3 #+END_SRC * Docker Compose Configuration ** Complete docker-compose.yml #+BEGIN_SRC yaml version: '3.8' services: icecast: image: infiniteproject/icecast:latest container_name: asteroid-icecast ports: - "8000:8000" volumes: - ./icecast.xml:/etc/icecast.xml environment: - ICECAST_SOURCE_PASSWORD=H1tn31EhsyLrfRmo - ICECAST_ADMIN_PASSWORD=asteroid_admin_2024 - ICECAST_RELAY_PASSWORD=asteroid_relay_2024 restart: unless-stopped networks: - asteroid-network liquidsoap: build: context: . dockerfile: Dockerfile.liquidsoap container_name: asteroid-liquidsoap ports: - "1234:1234" # Telnet control port depends_on: - icecast volumes: - ./music:/app/music:ro - ./asteroid-radio-docker.liq:/app/asteroid-radio.liq:ro restart: unless-stopped networks: - asteroid-network networks: asteroid-network: driver: bridge #+END_SRC * Container Configurations ** Icecast2 Container Setup *** Custom Icecast Configuration (icecast.xml) #+BEGIN_SRC xml Asteroid Radio Docker admin@asteroid-radio.docker 100 10 524288 30 15 10 1 H1tn31EhsyLrfRmo asteroid_relay_2024 admin asteroid_admin_2024 icecast 8000 0.0.0.0 /asteroid.mp3 source H1tn31EhsyLrfRmo 50 1 Asteroid Radio - High Quality http://localhost:8080/asteroid/ Electronic/Alternative 128 /asteroid.aac source H1tn31EhsyLrfRmo 50 1 Asteroid Radio - AAC Music for Hackers - 96kbps AAC http://localhost:8080/asteroid/ Electronic/Alternative 96 /asteroid-low.mp3 source H1tn31EhsyLrfRmo 100 1 Asteroid Radio - Low Quality Music for Hackers - 64kbps http://localhost:8080/asteroid/ Electronic/Alternative 64 1 /usr/share/icecast2 /var/log/icecast2 /usr/share/icecast2/web /usr/share/icecast2/admin access.log error.log 3 10000 #+END_SRC ** Liquidsoap Container Setup *** Liquidsoap Configuration (asteroid-radio-docker.liq) #+BEGIN_SRC liquidsoap #!/usr/bin/liquidsoap # Asteroid Radio - Docker streaming script # Streams music library continuously to Icecast2 running in Docker # Allow running as root in Docker set("init.allow_root", true) # Set log level for debugging log.level.set(4) # Enable telnet server for remote control settings.server.telnet.set(true) settings.server.telnet.port.set(1234) settings.server.telnet.bind_addr.set("0.0.0.0") # Create playlist source from mounted music directory radio = playlist( mode="randomize", reload=3600, reload_mode="watch", "/app/music/" ) # Add some audio processing radio = amplify(1.0, radio) radio = normalize(radio) # Add crossfade between tracks radio = crossfade(radio) # Create a fallback with emergency content emergency = sine(440.0) emergency = amplify(0.1, emergency) # Make source safe with fallback radio = fallback(track_sensitive=false, [radio, emergency]) # Add metadata radio = map_metadata(fun(m) -> [("title", m["title"] ?? "Unknown Track"), ("artist", m["artist"] ?? "Unknown Artist"), ("album", m["album"] ?? "Unknown Album")], radio) # High Quality MP3 Stream (128kbps) output.icecast( %mp3(bitrate=128), host="icecast", # Docker service name port=8000, password="H1tn31EhsyLrfRmo", mount="asteroid.mp3", name="Asteroid Radio", description="Music for Hackers - Streaming from the Asteroid", genre="Electronic/Alternative", url="http://localhost:8080/asteroid/", public=true, radio ) # AAC High Quality Stream (96kbps - better quality than 128kbps MP3) output.icecast( %fdkaac(bitrate=96), host="icecast", port=8000, password="H1tn31EhsyLrfRmo", mount="asteroid.aac", name="Asteroid Radio (AAC)", description="Music for Hackers - High efficiency AAC stream", genre="Electronic/Alternative", url="http://localhost:8080/asteroid/", public=true, radio ) # Low Quality MP3 Stream (for compatibility) output.icecast( %mp3(bitrate=64), host="icecast", port=8000, password="H1tn31EhsyLrfRmo", mount="asteroid-low.mp3", name="Asteroid Radio (Low Quality)", description="Music for Hackers - Low bandwidth stream", genre="Electronic/Alternative", url="http://localhost:8080/asteroid/", public=true, radio ) print("๐ŸŽต Asteroid Radio Docker streaming started!") print("High Quality MP3: http://localhost:8000/asteroid.mp3") print("High Quality AAC: http://localhost:8000/asteroid.aac") print("Low Quality MP3: http://localhost:8000/asteroid-low.mp3") print("Icecast Admin: http://localhost:8000/admin/") print("Telnet control: telnet localhost 1234") #+END_SRC * Management Scripts ** Start Script (start-streaming.sh) #+BEGIN_SRC bash #!/bin/bash # Asteroid Radio Docker Streaming Startup Script set -e echo "๐Ÿš€ Starting Asteroid Radio Docker Streaming..." # Check if Docker is running if ! docker info > /dev/null 2>&1; then echo "โŒ Docker is not running. Please start Docker first." exit 1 fi # Create required directories mkdir -p music/incoming music/library logs # Set permissions chmod 755 music/incoming music/library chmod 777 logs # Pull latest images echo "๐Ÿ“ฆ Pulling latest Docker images..." docker compose pull # Start services echo "๐ŸŽต Starting streaming services..." docker compose up -d # Wait for services to be ready echo "โณ Waiting for services to start..." sleep 10 # Check service status echo "๐Ÿ“Š Checking service status..." docker compose ps # Test connectivity echo "๐Ÿ” Testing streaming connectivity..." if curl -s -I http://localhost:8000/asteroid.mp3 | grep -q "200 OK"; then echo "โœ… High quality stream is working" else echo "โš ๏ธ High quality stream may not be ready yet" fi if curl -s -I http://localhost:8000/asteroid-low.mp3 | grep -q "200 OK"; then echo "โœ… Low quality MP3 stream is working" else echo "โš ๏ธ Low quality MP3 stream may not be ready yet" fi if curl -s -I http://localhost:8000/asteroid.aac | grep -q "200 OK"; then echo "โœ… AAC stream is working" else echo "โš ๏ธ AAC stream may not be ready yet" fi echo "" echo "๐ŸŽ‰ Asteroid Radio Docker setup complete!" echo "" echo "๐Ÿ“ป Stream URLs:" echo " High Quality MP3: http://localhost:8000/asteroid.mp3 (128kbps)" echo " High Quality AAC: http://localhost:8000/asteroid.aac (96kbps)" echo " Low Quality MP3: http://localhost:8000/asteroid-low.mp3 (64kbps)" echo "" echo "๐Ÿ”ง Admin Interfaces:" echo " Icecast: http://localhost:8000/admin/ (admin/asteroid_admin_2024)" echo " Telnet: telnet localhost 1234" echo "" echo "๐Ÿ“ Add music files to: ./music/" echo " Files are automatically detected and streamed." #+END_SRC ** Stop Script (stop-streaming.sh) #+BEGIN_SRC bash #!/bin/bash # Asteroid Radio Docker Streaming Stop Script echo "๐Ÿ›‘ Stopping Asteroid Radio Docker Streaming..." # Stop all services docker compose down # Optional: Remove volumes (uncomment to clean up completely) # docker compose down -v echo "โœ… All services stopped." #+END_SRC ** Test Script (test-streaming.sh) #+BEGIN_SRC bash #!/bin/bash # Asteroid Radio Docker Streaming Test Script echo "๐Ÿงช Testing Asteroid Radio Docker Setup..." # Test container status echo "๐Ÿ“Š Container Status:" docker compose ps echo "" echo "๐Ÿ” Testing Connectivity:" # Test Icecast2 if curl -s -I http://localhost:8000/ | grep -q "200 OK"; then echo "โœ… Icecast2 server is responding" else echo "โŒ Icecast2 server is not responding" fi # Test high quality stream if curl -s -I http://localhost:8000/asteroid.mp3 | grep -q "200 OK"; then echo "โœ… High quality stream is available" else echo "โŒ High quality stream is not available" fi # Test low quality stream if curl -s -I http://localhost:8000/asteroid-low.mp3 | grep -q "200 OK"; then echo "โœ… Low quality MP3 stream is available" else echo "โŒ Low quality MP3 stream is not available" fi # Test AAC stream if curl -s -I http://localhost:8000/asteroid.aac | grep -q "200 OK"; then echo "โœ… AAC stream is available" else echo "โŒ AAC stream is not available" fi echo "" echo "๐Ÿ“‹ Service Logs (last 10 lines):" echo "--- Icecast2 ---" docker compose logs --tail=10 icecast echo "--- Liquidsoap ---" docker compose logs --tail=10 liquidsoap #+END_SRC * Volume Management ** Music Library Setup #+BEGIN_SRC bash # Music directory already exists in repository # Copy sample music directly to the music directory cp ~/path/to/music/*.mp3 docker/music/ # Set permissions chmod 755 docker/music/ sudo chown -R $USER:$USER docker/music/ #+END_SRC ** Persistent Data - *Music Library*: =./music/= - Mounted as volume - *Logs*: =./logs/= - Container logs and streaming logs - *Configuration*: =./liquidsoap/= and =./icecast.xml= - Read-only configs * Networking ** Internal Container Network - Containers communicate via =asteroid-network= bridge - Liquidsoap connects to Icecast using hostname =icecast= - Telnet control available on port 1234 for Liquidsoap management ** External Access - *Port 8000*: Icecast2 streaming and admin interface - *Port 1234*: Liquidsoap telnet control interface - All services bind to =0.0.0.0= for external access ** WSL Compatibility #+BEGIN_SRC bash # Find WSL IP for external access ip addr show eth0 | grep inet # Access from Windows host # http://[IP-ADDRESS]:8000/asteroid.mp3 # 128kbps MP3 # http://[IP-ADDRESS]:8000/asteroid.aac # 96kbps AAC # http://[IP-ADDRESS]:8000/asteroid-low.mp3 # 64kbps MP3 #+END_SRC * Production Deployment ** Docker Swarm Setup #+BEGIN_SRC yaml # docker compose.prod.yml version: '3.8' services: icecast: image: moul/icecast deploy: replicas: 1 restart_policy: condition: on-failure # ... rest of configuration liquidsoap: image: savonet/liquidsoap:v2.2.x deploy: replicas: 1 restart_policy: condition: on-failure # ... rest of configuration #+END_SRC ** Environment Variables #+BEGIN_SRC bash # Production environment export ASTEROID_ENV=production export ASTEROID_STREAM_QUALITY=high export ASTEROID_MAX_LISTENERS=200 export ICECAST_ADMIN_PASSWORD=secure_password_here #+END_SRC ** SSL/TLS Setup Use reverse proxy (nginx/traefik) for HTTPS termination: #+BEGIN_SRC yaml # Add to docker-compose.yml nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/ssl:ro #+END_SRC * Monitoring and Logging ** Container Health Checks #+BEGIN_SRC bash # Check container health docker compose exec icecast curl -f http://localhost:8000/status.xsl docker compose exec liquidsoap ps aux | grep liquidsoap # Test telnet control interface echo "help" | nc localhost 1234 #+END_SRC ** Log Management #+BEGIN_SRC bash # View real-time logs docker compose logs -f # View specific service logs docker compose logs -f icecast docker compose logs -f liquidsoap # Log rotation setup docker run --log-driver=json-file --log-opt max-size=10m --log-opt max-file=3 #+END_SRC * Troubleshooting ** Common Docker Issues *** Container Won't Start #+BEGIN_SRC bash # Check container logs docker compose logs [service-name] # Check resource usage docker stats # Verify configuration files docker compose config #+END_SRC *** Streaming Issues #+BEGIN_SRC bash # Test internal connectivity docker compose exec liquidsoap ping icecast # Check Liquidsoap connection and logs docker compose logs liquidsoap # Test telnet interface echo "request.queue" | nc localhost 1234 #+END_SRC *** Permission Issues #+BEGIN_SRC bash # Fix music directory permissions sudo chown -R $USER:$USER docker/music/ chmod 755 docker/music/ #+END_SRC ** Performance Tuning *** Resource Limits #+BEGIN_SRC yaml # Add to services in docker-compose.yml deploy: resources: limits: memory: 512M cpus: '0.5' reservations: memory: 256M cpus: '0.25' #+END_SRC *** Network Optimization #+BEGIN_SRC yaml # Optimize network settings networks: asteroid-network: driver: bridge driver_opts: com.docker.network.driver.mtu: 1500 #+END_SRC This Docker streaming setup provides a complete containerized solution for Asteroid Radio with professional streaming capabilities and easy deployment.