/ docs / DOCKER-STREAMING.org
DOCKER-STREAMING.org
  1  #+TITLE: Asteroid Radio - Docker Streaming Setup
  2  #+AUTHOR: Asteroid Radio Development Team
  3  #+DATE: 2025-10-26
  4  
  5  * Docker Streaming Overview
  6  
  7  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.
  8  
  9  #+BEGIN_QUOTE
 10  *Note on Package Managers*: Examples use =apt= (Debian/Ubuntu). Replace with your distribution's package manager (=dnf=, =pacman=, =zypper=, =apk=, etc.).
 11  #+END_QUOTE
 12  
 13  * Architecture
 14  
 15  ** Container Stack
 16  - *Icecast2 Container*: Streaming server handling client connections
 17  - *Liquidsoap Container*: Audio processing and stream generation
 18  - *Shared Volumes*: Music library and configuration sharing
 19  
 20  ** Stream Formats
 21  - *High Quality MP3*: 128kbps MP3 stream at /asteroid.mp3
 22  - *High Quality AAC*: 96kbps AAC stream at /asteroid.aac (better efficiency than MP3)
 23  - *Low Quality MP3*: 64kbps MP3 stream at /asteroid-low.mp3 (compatibility)
 24  
 25  ** Network Configuration
 26  - *Icecast2*: Port 8000 (streaming and admin)
 27  - *Liquidsoap Telnet*: Port 1234 (remote control)
 28  - *Internal Network*: Container-to-container communication
 29  
 30  * Quick Start
 31  
 32  ** Prerequisites
 33  #+BEGIN_SRC bash
 34  # Install Docker and Docker Compose
 35  sudo apt update
 36  sudo apt install docker.io docker compose
 37  sudo usermod -a -G docker $USER
 38  # Log out and back in for group changes
 39  #+END_SRC
 40  
 41  ** One-Command Setup
 42  #+BEGIN_SRC bash
 43  # Clone and start
 44  git clone https://github.com/fade/asteroid asteroid-radio
 45  cd asteroid-radio/docker
 46  docker compose up -d
 47  #+END_SRC
 48  
 49  ** Verify Setup
 50  #+BEGIN_SRC bash
 51  # Check container status
 52  docker compose ps
 53  
 54  # Test streaming (all three formats)
 55  curl -I http://localhost:8000/asteroid.mp3     # 128kbps MP3
 56  curl -I http://localhost:8000/asteroid.aac     # 96kbps AAC
 57  curl -I http://localhost:8000/asteroid-low.mp3 # 64kbps MP3
 58  #+END_SRC
 59  
 60  * Docker Compose Configuration
 61  
 62  ** Complete docker-compose.yml
 63  #+BEGIN_SRC yaml
 64  version: '3.8'
 65  
 66  services:
 67    icecast:
 68      image: infiniteproject/icecast:latest
 69      container_name: asteroid-icecast
 70      ports:
 71        - "8000:8000"
 72      volumes:
 73        - ./icecast.xml:/etc/icecast.xml
 74      environment:
 75        - ICECAST_SOURCE_PASSWORD=H1tn31EhsyLrfRmo
 76        - ICECAST_ADMIN_PASSWORD=asteroid_admin_2024
 77        - ICECAST_RELAY_PASSWORD=asteroid_relay_2024
 78      restart: unless-stopped
 79      networks:
 80        - asteroid-network
 81  
 82    liquidsoap:
 83      build:
 84        context: .
 85        dockerfile: Dockerfile.liquidsoap
 86      container_name: asteroid-liquidsoap
 87      ports:
 88        - "1234:1234"  # Telnet control port
 89      depends_on:
 90        - icecast
 91      volumes:
 92        - ./music:/app/music:ro
 93        - ./asteroid-radio-docker.liq:/app/asteroid-radio.liq:ro
 94      restart: unless-stopped
 95      networks:
 96        - asteroid-network
 97  
 98  networks:
 99    asteroid-network:
100      driver: bridge
101  #+END_SRC
102  
103  * Container Configurations
104  
105  ** Icecast2 Container Setup
106  
107  *** Custom Icecast Configuration (icecast.xml)
108  #+BEGIN_SRC xml
109  <icecast>
110      <location>Asteroid Radio Docker</location>
111      <admin>admin@asteroid-radio.docker</admin>
112      
113      <limits>
114          <clients>100</clients>
115          <sources>10</sources>
116          <queue-size>524288</queue-size>
117          <client-timeout>30</client-timeout>
118          <header-timeout>15</header-timeout>
119          <source-timeout>10</source-timeout>
120          <burst-on-connect>1</burst-on-connect>
121      </limits>
122      
123      <authentication>
124          <source-password>H1tn31EhsyLrfRmo</source-password>
125          <relay-password>asteroid_relay_2024</relay-password>
126          <admin-user>admin</admin-user>
127          <admin-password>asteroid_admin_2024</admin-password>
128      </authentication>
129      
130      <hostname>icecast</hostname>
131      <listen-socket>
132          <port>8000</port>
133          <bind-address>0.0.0.0</bind-address>
134      </listen-socket>
135      
136      <!-- High Quality Stream -->
137      <mount type="normal">
138          <mount-name>/asteroid.mp3</mount-name>
139          <username>source</username>
140          <password>H1tn31EhsyLrfRmo</password>
141          <max-listeners>50</max-listeners>
142          <public>1</public>
143          <stream-name>Asteroid Radio - High Quality</stream-name>
144          <stream-url>http://localhost:8080/asteroid/</stream-url>
145          <genre>Electronic/Alternative</genre>
146          <bitrate>128</bitrate>
147      </mount>
148      
149      <!-- AAC High Quality Stream -->
150      <mount type="normal">
151          <mount-name>/asteroid.aac</mount-name>
152          <username>source</username>
153          <password>H1tn31EhsyLrfRmo</password>
154          <max-listeners>50</max-listeners>
155          <public>1</public>
156          <stream-name>Asteroid Radio - AAC</stream-name>
157          <stream-description>Music for Hackers - 96kbps AAC</stream-description>
158          <stream-url>http://localhost:8080/asteroid/</stream-url>
159          <genre>Electronic/Alternative</genre>
160          <bitrate>96</bitrate>
161      </mount>
162      
163      <!-- Low Quality Stream -->
164      <mount type="normal">
165          <mount-name>/asteroid-low.mp3</mount-name>
166          <username>source</username>
167          <password>H1tn31EhsyLrfRmo</password>
168          <max-listeners>100</max-listeners>
169          <public>1</public>
170          <stream-name>Asteroid Radio - Low Quality</stream-name>
171          <stream-description>Music for Hackers - 64kbps</stream-description>
172          <stream-url>http://localhost:8080/asteroid/</stream-url>
173          <genre>Electronic/Alternative</genre>
174          <bitrate>64</bitrate>
175      </mount>
176      
177      <fileserve>1</fileserve>
178      <paths>
179          <basedir>/usr/share/icecast2</basedir>
180          <logdir>/var/log/icecast2</logdir>
181          <webroot>/usr/share/icecast2/web</webroot>
182          <adminroot>/usr/share/icecast2/admin</adminroot>
183          <alias source="/" destination="/status.xsl"/>
184      </paths>
185      
186      <logging>
187          <accesslog>access.log</accesslog>
188          <errorlog>error.log</errorlog>
189          <loglevel>3</loglevel>
190          <logsize>10000</logsize>
191      </logging>
192  </icecast>
193  #+END_SRC
194  
195  ** Liquidsoap Container Setup
196  
197  *** Liquidsoap Configuration (asteroid-radio-docker.liq)
198  #+BEGIN_SRC liquidsoap
199  #!/usr/bin/liquidsoap
200  
201  # Asteroid Radio - Docker streaming script
202  # Streams music library continuously to Icecast2 running in Docker
203  
204  # Allow running as root in Docker
205  set("init.allow_root", true)
206  
207  # Set log level for debugging
208  log.level.set(4)
209  
210  # Enable telnet server for remote control
211  settings.server.telnet.set(true)
212  settings.server.telnet.port.set(1234)
213  settings.server.telnet.bind_addr.set("0.0.0.0")
214  
215  # Create playlist source from mounted music directory
216  radio = playlist(
217    mode="randomize", 
218    reload=3600, 
219    reload_mode="watch",
220    "/app/music/"
221  )
222  
223  # Add some audio processing
224  radio = amplify(1.0, radio)
225  radio = normalize(radio)
226  
227  # Add crossfade between tracks
228  radio = crossfade(radio)
229  
230  # Create a fallback with emergency content
231  emergency = sine(440.0)
232  emergency = amplify(0.1, emergency)
233  
234  # Make source safe with fallback
235  radio = fallback(track_sensitive=false, [radio, emergency])
236  
237  # Add metadata
238  radio = map_metadata(fun(m) -> 
239    [("title", m["title"] ?? "Unknown Track"),
240     ("artist", m["artist"] ?? "Unknown Artist"),
241     ("album", m["album"] ?? "Unknown Album")], radio)
242  
243  # High Quality MP3 Stream (128kbps)
244  output.icecast(
245    %mp3(bitrate=128),
246    host="icecast",  # Docker service name
247    port=8000,
248    password="H1tn31EhsyLrfRmo",
249    mount="asteroid.mp3",
250    name="Asteroid Radio",
251    description="Music for Hackers - Streaming from the Asteroid",
252    genre="Electronic/Alternative",
253    url="http://localhost:8080/asteroid/",
254    public=true,
255    radio
256  )
257  
258  # AAC High Quality Stream (96kbps - better quality than 128kbps MP3)
259  output.icecast(
260    %fdkaac(bitrate=96),
261    host="icecast",
262    port=8000,
263    password="H1tn31EhsyLrfRmo",
264    mount="asteroid.aac",
265    name="Asteroid Radio (AAC)",
266    description="Music for Hackers - High efficiency AAC stream",
267    genre="Electronic/Alternative",
268    url="http://localhost:8080/asteroid/",
269    public=true,
270    radio
271  )
272  
273  # Low Quality MP3 Stream (for compatibility)
274  output.icecast(
275    %mp3(bitrate=64),
276    host="icecast",
277    port=8000,
278    password="H1tn31EhsyLrfRmo",
279    mount="asteroid-low.mp3",
280    name="Asteroid Radio (Low Quality)",
281    description="Music for Hackers - Low bandwidth stream",
282    genre="Electronic/Alternative",
283    url="http://localhost:8080/asteroid/",
284    public=true,
285    radio
286  )
287  
288  print("๐ŸŽต Asteroid Radio Docker streaming started!")
289  print("High Quality MP3:  http://localhost:8000/asteroid.mp3")
290  print("High Quality AAC:  http://localhost:8000/asteroid.aac")
291  print("Low Quality MP3:   http://localhost:8000/asteroid-low.mp3")
292  print("Icecast Admin:     http://localhost:8000/admin/")
293  print("Telnet control:    telnet localhost 1234")
294  #+END_SRC
295  
296  
297  * Management Scripts
298  
299  ** Start Script (start-streaming.sh)
300  #+BEGIN_SRC bash
301  #!/bin/bash
302  
303  # Asteroid Radio Docker Streaming Startup Script
304  
305  set -e
306  
307  echo "๐Ÿš€ Starting Asteroid Radio Docker Streaming..."
308  
309  # Check if Docker is running
310  if ! docker info > /dev/null 2>&1; then
311      echo "โŒ Docker is not running. Please start Docker first."
312      exit 1
313  fi
314  
315  # Create required directories
316  mkdir -p music/incoming music/library logs
317  
318  # Set permissions
319  chmod 755 music/incoming music/library
320  chmod 777 logs
321  
322  # Pull latest images
323  echo "๐Ÿ“ฆ Pulling latest Docker images..."
324  docker compose pull
325  
326  # Start services
327  echo "๐ŸŽต Starting streaming services..."
328  docker compose up -d
329  
330  # Wait for services to be ready
331  echo "โณ Waiting for services to start..."
332  sleep 10
333  
334  # Check service status
335  echo "๐Ÿ“Š Checking service status..."
336  docker compose ps
337  
338  # Test connectivity
339  echo "๐Ÿ” Testing streaming connectivity..."
340  if curl -s -I http://localhost:8000/asteroid.mp3 | grep -q "200 OK"; then
341      echo "โœ… High quality stream is working"
342  else
343      echo "โš ๏ธ  High quality stream may not be ready yet"
344  fi
345  
346  if curl -s -I http://localhost:8000/asteroid-low.mp3 | grep -q "200 OK"; then
347      echo "โœ… Low quality MP3 stream is working"
348  else
349      echo "โš ๏ธ  Low quality MP3 stream may not be ready yet"
350  fi
351  
352  if curl -s -I http://localhost:8000/asteroid.aac | grep -q "200 OK"; then
353      echo "โœ… AAC stream is working"
354  else
355      echo "โš ๏ธ  AAC stream may not be ready yet"
356  fi
357  
358  echo ""
359  echo "๐ŸŽ‰ Asteroid Radio Docker setup complete!"
360  echo ""
361  echo "๐Ÿ“ป Stream URLs:"
362  echo "   High Quality MP3: http://localhost:8000/asteroid.mp3 (128kbps)"
363  echo "   High Quality AAC: http://localhost:8000/asteroid.aac (96kbps)"
364  echo "   Low Quality MP3:  http://localhost:8000/asteroid-low.mp3 (64kbps)"
365  echo ""
366  echo "๐Ÿ”ง Admin Interfaces:"
367  echo "   Icecast:      http://localhost:8000/admin/ (admin/asteroid_admin_2024)"
368  echo "   Telnet:       telnet localhost 1234"
369  echo ""
370  echo "๐Ÿ“ Add music files to: ./music/"
371  echo "   Files are automatically detected and streamed."
372  #+END_SRC
373  
374  ** Stop Script (stop-streaming.sh)
375  #+BEGIN_SRC bash
376  #!/bin/bash
377  
378  # Asteroid Radio Docker Streaming Stop Script
379  
380  echo "๐Ÿ›‘ Stopping Asteroid Radio Docker Streaming..."
381  
382  # Stop all services
383  docker compose down
384  
385  # Optional: Remove volumes (uncomment to clean up completely)
386  # docker compose down -v
387  
388  echo "โœ… All services stopped."
389  #+END_SRC
390  
391  ** Test Script (test-streaming.sh)
392  #+BEGIN_SRC bash
393  #!/bin/bash
394  
395  # Asteroid Radio Docker Streaming Test Script
396  
397  echo "๐Ÿงช Testing Asteroid Radio Docker Setup..."
398  
399  # Test container status
400  echo "๐Ÿ“Š Container Status:"
401  docker compose ps
402  
403  echo ""
404  echo "๐Ÿ” Testing Connectivity:"
405  
406  # Test Icecast2
407  if curl -s -I http://localhost:8000/ | grep -q "200 OK"; then
408      echo "โœ… Icecast2 server is responding"
409  else
410      echo "โŒ Icecast2 server is not responding"
411  fi
412  
413  # Test high quality stream
414  if curl -s -I http://localhost:8000/asteroid.mp3 | grep -q "200 OK"; then
415      echo "โœ… High quality stream is available"
416  else
417      echo "โŒ High quality stream is not available"
418  fi
419  
420  # Test low quality stream
421  if curl -s -I http://localhost:8000/asteroid-low.mp3 | grep -q "200 OK"; then
422      echo "โœ… Low quality MP3 stream is available"
423  else
424      echo "โŒ Low quality MP3 stream is not available"
425  fi
426  
427  # Test AAC stream
428  if curl -s -I http://localhost:8000/asteroid.aac | grep -q "200 OK"; then
429      echo "โœ… AAC stream is available"
430  else
431      echo "โŒ AAC stream is not available"
432  fi
433  
434  echo ""
435  echo "๐Ÿ“‹ Service Logs (last 10 lines):"
436  echo "--- Icecast2 ---"
437  docker compose logs --tail=10 icecast
438  
439  echo "--- Liquidsoap ---"
440  docker compose logs --tail=10 liquidsoap
441  
442  #+END_SRC
443  
444  * Volume Management
445  
446  ** Music Library Setup
447  #+BEGIN_SRC bash
448  # Music directory already exists in repository
449  # Copy sample music directly to the music directory
450  cp ~/path/to/music/*.mp3 docker/music/
451  
452  # Set permissions
453  chmod 755 docker/music/
454  sudo chown -R $USER:$USER docker/music/
455  #+END_SRC
456  
457  ** Persistent Data
458  - *Music Library*: =./music/= - Mounted as volume
459  - *Logs*: =./logs/= - Container logs and streaming logs
460  - *Configuration*: =./liquidsoap/= and =./icecast.xml= - Read-only configs
461  
462  * Networking
463  
464  ** Internal Container Network
465  - Containers communicate via =asteroid-network= bridge
466  - Liquidsoap connects to Icecast using hostname =icecast=
467  - Telnet control available on port 1234 for Liquidsoap management
468  
469  ** External Access
470  - *Port 8000*: Icecast2 streaming and admin interface
471  - *Port 1234*: Liquidsoap telnet control interface
472  - All services bind to =0.0.0.0= for external access
473  
474  ** WSL Compatibility
475  #+BEGIN_SRC bash
476  # Find WSL IP for external access
477  ip addr show eth0 | grep inet
478  
479  # Access from Windows host
480  # http://[IP-ADDRESS]:8000/asteroid.mp3     # 128kbps MP3
481  # http://[IP-ADDRESS]:8000/asteroid.aac     # 96kbps AAC  
482  # http://[IP-ADDRESS]:8000/asteroid-low.mp3 # 64kbps MP3
483  #+END_SRC
484  
485  * Production Deployment
486  
487  ** Docker Swarm Setup
488  #+BEGIN_SRC yaml
489  # docker compose.prod.yml
490  version: '3.8'
491  
492  services:
493    icecast:
494      image: moul/icecast
495      deploy:
496        replicas: 1
497        restart_policy:
498          condition: on-failure
499      # ... rest of configuration
500  
501    liquidsoap:
502      image: savonet/liquidsoap:v2.2.x
503      deploy:
504        replicas: 1
505        restart_policy:
506          condition: on-failure
507      # ... rest of configuration
508  #+END_SRC
509  
510  ** Environment Variables
511  #+BEGIN_SRC bash
512  # Production environment
513  export ASTEROID_ENV=production
514  export ASTEROID_STREAM_QUALITY=high
515  export ASTEROID_MAX_LISTENERS=200
516  export ICECAST_ADMIN_PASSWORD=secure_password_here
517  #+END_SRC
518  
519  ** SSL/TLS Setup
520  Use reverse proxy (nginx/traefik) for HTTPS termination:
521  #+BEGIN_SRC yaml
522  # Add to docker-compose.yml
523    nginx:
524      image: nginx:alpine
525      ports:
526        - "80:80"
527        - "443:443"
528      volumes:
529        - ./nginx.conf:/etc/nginx/nginx.conf:ro
530        - ./ssl:/etc/ssl:ro
531  #+END_SRC
532  
533  * Monitoring and Logging
534  
535  ** Container Health Checks
536  #+BEGIN_SRC bash
537  # Check container health
538  docker compose exec icecast curl -f http://localhost:8000/status.xsl
539  docker compose exec liquidsoap ps aux | grep liquidsoap
540  
541  # Test telnet control interface
542  echo "help" | nc localhost 1234
543  #+END_SRC
544  
545  ** Log Management
546  #+BEGIN_SRC bash
547  # View real-time logs
548  docker compose logs -f
549  
550  # View specific service logs
551  docker compose logs -f icecast
552  docker compose logs -f liquidsoap
553  
554  # Log rotation setup
555  docker run --log-driver=json-file --log-opt max-size=10m --log-opt max-file=3
556  #+END_SRC
557  
558  * Troubleshooting
559  
560  ** Common Docker Issues
561  
562  *** Container Won't Start
563  #+BEGIN_SRC bash
564  # Check container logs
565  docker compose logs [service-name]
566  
567  # Check resource usage
568  docker stats
569  
570  # Verify configuration files
571  docker compose config
572  #+END_SRC
573  
574  *** Streaming Issues
575  #+BEGIN_SRC bash
576  # Test internal connectivity
577  docker compose exec liquidsoap ping icecast
578  
579  # Check Liquidsoap connection and logs
580  docker compose logs liquidsoap
581  
582  # Test telnet interface
583  echo "request.queue" | nc localhost 1234
584  #+END_SRC
585  
586  *** Permission Issues
587  #+BEGIN_SRC bash
588  # Fix music directory permissions
589  sudo chown -R $USER:$USER docker/music/
590  chmod 755 docker/music/
591  #+END_SRC
592  
593  ** Performance Tuning
594  
595  *** Resource Limits
596  #+BEGIN_SRC yaml
597  # Add to services in docker-compose.yml
598      deploy:
599        resources:
600          limits:
601            memory: 512M
602            cpus: '0.5'
603          reservations:
604            memory: 256M
605            cpus: '0.25'
606  #+END_SRC
607  
608  *** Network Optimization
609  #+BEGIN_SRC yaml
610  # Optimize network settings
611  networks:
612    asteroid-network:
613      driver: bridge
614      driver_opts:
615        com.docker.network.driver.mtu: 1500
616  #+END_SRC
617  
618  This Docker streaming setup provides a complete containerized solution for Asteroid Radio with professional streaming capabilities and easy deployment.