asteroid/docs/DOCKER-STREAMING.org

16 KiB

Asteroid Radio - Docker Streaming Setup

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

# 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

One-Command Setup

# Clone and start
git clone https://github.com/fade/asteroid asteroid-radio
cd asteroid-radio/docker
docker compose up -d

Verify Setup

# 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

Docker Compose Configuration

Complete docker-compose.yml

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

Container Configurations

Icecast2 Container Setup

Custom Icecast Configuration (icecast.xml)

<icecast>
    <location>Asteroid Radio Docker</location>
    <admin>admin@asteroid-radio.docker</admin>
    
    <limits>
        <clients>100</clients>
        <sources>10</sources>
        <queue-size>524288</queue-size>
        <client-timeout>30</client-timeout>
        <header-timeout>15</header-timeout>
        <source-timeout>10</source-timeout>
        <burst-on-connect>1</burst-on-connect>
    </limits>
    
    <authentication>
        <source-password>H1tn31EhsyLrfRmo</source-password>
        <relay-password>asteroid_relay_2024</relay-password>
        <admin-user>admin</admin-user>
        <admin-password>asteroid_admin_2024</admin-password>
    </authentication>
    
    <hostname>icecast</hostname>
    <listen-socket>
        <port>8000</port>
        <bind-address>0.0.0.0</bind-address>
    </listen-socket>
    
    <!-- High Quality Stream -->
    <mount type="normal">
        <mount-name>/asteroid.mp3</mount-name>
        <username>source</username>
        <password>H1tn31EhsyLrfRmo</password>
        <max-listeners>50</max-listeners>
        <public>1</public>
        <stream-name>Asteroid Radio - High Quality</stream-name>
        <stream-url>http://localhost:8080/asteroid/</stream-url>
        <genre>Electronic/Alternative</genre>
        <bitrate>128</bitrate>
    </mount>
    
    <!-- AAC High Quality Stream -->
    <mount type="normal">
        <mount-name>/asteroid.aac</mount-name>
        <username>source</username>
        <password>H1tn31EhsyLrfRmo</password>
        <max-listeners>50</max-listeners>
        <public>1</public>
        <stream-name>Asteroid Radio - AAC</stream-name>
        <stream-description>Music for Hackers - 96kbps AAC</stream-description>
        <stream-url>http://localhost:8080/asteroid/</stream-url>
        <genre>Electronic/Alternative</genre>
        <bitrate>96</bitrate>
    </mount>
    
    <!-- Low Quality Stream -->
    <mount type="normal">
        <mount-name>/asteroid-low.mp3</mount-name>
        <username>source</username>
        <password>H1tn31EhsyLrfRmo</password>
        <max-listeners>100</max-listeners>
        <public>1</public>
        <stream-name>Asteroid Radio - Low Quality</stream-name>
        <stream-description>Music for Hackers - 64kbps</stream-description>
        <stream-url>http://localhost:8080/asteroid/</stream-url>
        <genre>Electronic/Alternative</genre>
        <bitrate>64</bitrate>
    </mount>
    
    <fileserve>1</fileserve>
    <paths>
        <basedir>/usr/share/icecast2</basedir>
        <logdir>/var/log/icecast2</logdir>
        <webroot>/usr/share/icecast2/web</webroot>
        <adminroot>/usr/share/icecast2/admin</adminroot>
        <alias source="/" destination="/status.xsl"/>
    </paths>
    
    <logging>
        <accesslog>access.log</accesslog>
        <errorlog>error.log</errorlog>
        <loglevel>3</loglevel>
        <logsize>10000</logsize>
    </logging>
</icecast>

Liquidsoap Container Setup

Liquidsoap Configuration (asteroid-radio-docker.liq)

#!/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")

Management Scripts

Start Script (start-streaming.sh)

#!/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."

Stop Script (stop-streaming.sh)

#!/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."

Test Script (test-streaming.sh)

#!/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

Volume Management

Music Library Setup

# 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/

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

# 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

Production Deployment

Docker Swarm Setup

# 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

Environment Variables

# Production environment
export ASTEROID_ENV=production
export ASTEROID_STREAM_QUALITY=high
export ASTEROID_MAX_LISTENERS=200
export ICECAST_ADMIN_PASSWORD=secure_password_here

SSL/TLS Setup

Use reverse proxy (nginx/traefik) for HTTPS termination:

# 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

Monitoring and Logging

Container Health Checks

# 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

Log Management

# 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

Troubleshooting

Common Docker Issues

Container Won't Start

# Check container logs
docker compose logs [service-name]

# Check resource usage
docker stats

# Verify configuration files
docker compose config

Streaming Issues

# 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

Permission Issues

# Fix music directory permissions
sudo chown -R $USER:$USER docker/music/
chmod 755 docker/music/

Performance Tuning

Resource Limits

# Add to services in docker-compose.yml
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: '0.5'
        reservations:
          memory: 256M
          cpus: '0.25'

Network Optimization

# Optimize network settings
networks:
  asteroid-network:
    driver: bridge
    driver_opts:
      com.docker.network.driver.mtu: 1500

This Docker streaming setup provides a complete containerized solution for Asteroid Radio with professional streaming capabilities and easy deployment.