Building an Online Jukebox

I've always wanted my own internet music radio, where I can just open it and music would start flowing into my ears. I don't want to choose what music to listen to, just want to start listening right away. Wouldn't it be cool everybody on the website is listening at the exact same sound.

setting up a new domain and a reverse proxy

So I registered this cool domain name chillbeats.live, changed the nameservers to CloudFlare's and added CNAME record on their DNS page to point the domain to project.enting.org. The only problem is, I need a reverse web proxy to redirect to a different port than port 80 when the request uses chillbeats' hostname.

So, let's set up an Nginx reverse proxy with Docker.

While I was researching on Google, a Github project called nginx-proxy caught my eyes, It does what I want and more. Not only does it sets up the Nginx reverse proxy, it also does it automagically.

To set up the Nginx proxy: docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy

To run a test web app container: docker run -e VIRTUAL_HOST=chillbeats.live -d --name web-test crccheck/hello-world. This container expose port 8000, which is picked up automatically by Nginx proxy, and results in no port conflict on the host.

And curl chillbeats.live. Voila:

<xmp>
Hello World


                                       ##         .
                                 ## ## ##        ==
                              ## ## ## ## ##    ===
                           /""""""""""""""""\___/ ===
                      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
                           \______ o          _,/
                            \      \       _,'
                             `'--.._\..--''
</xmp>

Amazing!

Building the Music Jukebox Radio

The popular audio streaming solution is icecast along with liquidsoap.

For security concerns, I don't want to expose icecast server to the public, so we need an Nginx server inside the docker container to proxy only the audio stream url to the public.

The nginx config file looks like this:

server {
        listen 80;
        server_name chillbeats.live;

        location / {
                root /var/www/html;
                index index.html;
                try_files $uri $uri/index.html $uri.html =404;
        }

        location /audio.mp3 {
                proxy_pass http://localhost:8000/audio.mp3;
        }
}

After some trials and errors, the final Dockerfile looks like this:

FROM ubuntu:xenial

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y sudo liquidsoap icecast2

RUN useradd ices && mkdir -p /var/log/icecast2 && touch /var/log/icecast2/error.log && touch /var/log/icecast2/access.log && chown ices /var/log/icecast2/error.log && chown ices /var/log/icecast2/access.log && chown ices /var/log/icecast2/error.log && chown ices /etc/icecast2/icecast.xml

EXPOSE 80

ADD icecast.xml /etc/icecast2/icecast.xml

RUN mkdir -p /var/run/liquidsoap
RUN touch /var/run/liquidsoap/default.pid
RUN sudo chown ices /var/run/liquidsoap/default.pid

RUN apt-get install -y nginx
ADD nginx.conf /etc/nginx/sites-enabled/default
ADD bg.jpg /var/www/html/bg.jpg
ADD index.html /var/www/html/index.html
ADD audios/1.mp3 1.mp3

CMD icecast2 -c /etc/icecast2/icecast.xml -b && sudo -u ices liquidsoap --daemon 'output.icecast(%mp3, host = "localhost", port = 8000, password = "goss-miz", mount = "audio.mp3", mksafe(single("1.mp3")))' && nginx -g 'daemon off;'

I also made a Makefile to help with build and run:

run:
        docker run -d -e VIRTUAL_HOST=chillbeats.live dohsimpson/chillbeats
build:
        docker build -t dohsimpson/chillbeats .

After launching the container, nginx-proxy automatically takes care of reverse proxying the hostname to the container port.

So Check it out at chillbeats.live

Screen-Shot-2018-04-03-at-1.18.15-PM

So chill...

Music credit goes to: Le Tournedisque
Photo credit goes to: Alphacolor 13 on Unsplash

[Finish time: around 5 hours]


UPDATE: 2018-04-05 changed the last two lines of the Dockerfile to the following to loop all audios in a directory:

ADD audios /audios

RUN sudo chown -R ices /audios

CMD icecast2 -c /etc/icecast2/icecast.xml -b && sudo -u ices liquidsoap --daemon 'output.icecast(%mp3, host = "localhost", port = 8000, password = "goss-miz", mount = "audio.mp3", mksafe(playlist("/audios")))' && nginx -g 'daemon off;'