Koel is a web-based audio streaming service written in the Laravel PHP framework. It allows you to stream your personal music collection and access it from anywhere in the world. It supports multiple media formats, including AAC, OGG, WMA, FLAC, and APE.

In this tutorial, you will learn how to install Koel Music Streaming Server using Docker on a Rocky Linux 8 machine.

Prerequisites

  • A Server running Rocky Linux 8.5.

  • A non-root user with sudo privileges.

  • Update everything.

    $ sudo dnf update
    
  • Install essential packages.

    $ sudo dnf install yum-utils nano curl
    
  • A custom domain name pointing to the server like koel.example.com.

Step 1 – Configure Firewall

The first step is to configure the firewall. Rocky Linux uses Firewalld Firewall. Check the firewall’s status.

$ sudo firewall-cmd --state
running

The firewall works with different zones, and the public zone is the default one that we will use. List all the services and ports active on the firewall.

$ sudo firewall-cmd --permanent --list-services

It should show the following output.

cockpit dhcpv6-client ssh

Allow HTTP and HTTPS ports.

$ sudo firewall-cmd --permanent --add-service=http
$ sudo firewall-cmd --permanent --add-service=https

Recheck the status of the firewall.

$ sudo firewall-cmd --permanent --list-services

You should see a similar output.

cockpit dhcpv6-client http https ssh

Reload the firewall to enable the changes.

$ sudo firewall-cmd --reload

Step 2 – Install Docker

Rocky Linux ships with an older version of Docker. To install the latest version, first, install the official Docker repository.

$ sudo yum-config-manager 
    --add-repo 
    https://download.docker.com/linux/centos/docker-ce.repo

Install the latest version of Docker.

$ sudo dnf install docker-ce docker-ce-cli containerd.io

Enable and run the Docker daemon.

$ sudo systemctl enable docker --now

Verify that it is running.

? docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2022-04-02 13:26:08 UTC; 2s ago
     Docs: https://docs.docker.com
 Main PID: 21152 (dockerd)
    Tasks: 7
   Memory: 30.9M
   CGroup: /system.slice/docker.service
           ??21152 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
...

By default, Docker requires root privileges. If you want to avoid using sudo every time you run the docker command, add your username to the docker group.

$ sudo usermod -aG docker $(whoami)

You will need to log out of the server and back in as the same user to enable this change.

Step 3 – Install Docker Compose

Download the latest stable release of Docker Compose.

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

Apply executable permissions to the Docker Compose binary file.

$ sudo chmod  x /usr/local/bin/docker-compose

Test the installation.

$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c

Install the Docker-compose Bash Completion script.

$ sudo curl 
    -L https://raw.githubusercontent.com/docker/compose/1.29.2/contrib/completion/bash/docker-compose 
    -o /etc/bash_completion.d/docker-compose

Reload your profile settings to make the bash-completion work.

$ source ~/.bashrc

Step 4 – Create Koel App Key

We will generate Koel’s App key by running the container for a short moment. Run the following command to run the container and access its shell.

$ docker run -it --rm phanan/koel bash

Once in the container, run the following command to generate the application key.

$ php artisan key:generate --force

Output the modified environment file with the newly generated app key.

$ cat .env
APP_KEY=base64:fjtO7aVHHKWfk4DThKqf1nci6o2DuMkNd90TKX6Gj 4=

Copy the key value and exit the container shell.

$ exit

Step 5 – Create Koel Environment File

Create a directory for Koel.Advertisement

$ mkdir ~/koel

Switch to the directory.

$ cd ~/koel

Create the music directory.

$ mkdir music

Create and open the .env file.

$ nano .env

Paste the following code in it.

APP_NAME=Koel

# A random 32-char string. You can leave this empty if use php artisan koel:init.
APP_KEY=base64:fjtO7aVHHKWfk4DThKqf1nci6o2DuMkNd90TKX6Gj 4=

# The ABSOLUTE path to your media. This value can always be changed later via the web interface.
MEDIA_PATH=/music

APP_ENV=production
APP_DEBUG=true
APP_URL=https://koel.example.com

# The maximum scan time, in seconds. Increase this if you have a huge library.
# Note: This setting doesn't have effect when scanning via koel:sync.
APP_MAX_SCAN_TIME=600

# The memory limit, in MB, used by the scanning process.
# For example, if you want to set a memory limit of 2048MB, enter "2048" (without
# quotes) here.
MEMORY_LIMIT=512

# The streaming method.
# Can be either 'php' (default), 'x-sendfile', or 'x-accel-redirect'
# See https://docs.koel.dev/#streaming-music for more information.
# Note: This setting doesn't have effect if the media needs transcoding (e.g. FLAC).
STREAMING_METHOD=x-sendfile

# If you want Koel to integrate with Last.fm, set the API details here.
# See https://docs.koel.dev/3rd-party.html#last-fm for more information
LASTFM_API_KEY=
LASTFM_API_SECRET=

# If you want to use Amazon S3 with Koel, fill the info here and follow the
# installation guide at https://docs.koel.dev/aws-s3.html
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=

# If you want Koel to integrate with YouTube, set the API key here.
# See https://docs.koel.dev/3rd-party.html#youtube for more information.
YOUTUBE_API_KEY=

# You can also configure Koel to use a CDN to serve the media files.
# This url must be mapped to the home URL of your Koel's installation.
# No trailing slash, please.
CDN_URL=

# The bit rate of the output mp3 stream. Higher value results in better quality,
# but slower streaming and more bandwidth.
OUTPUT_BIT_RATE=128

# Whether to allow song downloading.
# Note that if you're downloading more than one song, Koel will zip them up
# using PHP's ZipArchive. So if the module isn't available in the current
# environment, such a download will (silently) fail.
ALLOW_DOWNLOAD=true

# If this is set to true, the query to get artist, album, and song information will be cached.
# This can give a boost to Koel's boot time, especially if your library is huge.
# However, the cache deserialization process can be memory sensitive, so if you encounter
# errors, try setting this to false.
CACHE_MEDIA=true

# Koel attempts to detect if your website use HTTPS and generates secure URLs accordingly.
# If this attempts for any reason, you can force it by setting this value to true.
FORCE_HTTPS=true

# The variables below are Laravel-specific.
# You can change them if you know what you're doing. Otherwise, just leave them as-is.
APP_LOG_LEVEL=debug
BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync

Save the file by pressing Ctrl X and entering Y when prompted.

Most of the settings are self-explanatory above. The following settings need to be configured to make it work. Paste the app key generated in the previous step against the APP_KEY variable. Enter your domain name under APP_URL, and set the memory limit in MBs depending on your server’s resources. We have set the streaming method to x-sendfile as Koel’s docker image uses Apache and comes pre-configured with it. The FORCE_HTTPS setting is set to true because we will use Nginx as a load balancer along with Let’s Encrypt SSL to serve Koel to the web. Configure other services if you want to use them along with Koel.

Step 6 – Create Koel Docker Compose File

Create and open the file docker-compose.yml for editing.

$ nano docker-compose.yml

Paste the following code into it.

version: '3.3'

services:
  koel:
    image: phanan/koel
    container_name: koel
    depends_on:
      - koeldb
    restart: unless-stopped
    ports:
      - 8080:80
    environment:
      - DB_CONNECTION=mysql
      - DB_HOST=koeldb
      - DB_USERNAME=koel
      - DB_PASSWORD=koelpassword
      - DB_DATABASE=koel
    volumes:
      - ./music:/music
      - ./.env:/var/www/html/.env
      - covers:/var/www/html/public/img/covers
      - search_index:/var/www/html/storage/search-indexes

  koeldb:
    image: mysql/mysql-server:8.0
    restart: unless-stopped
    volumes:
      - db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword
      - MYSQL_DATABASE=koel
      - MYSQL_USER=koel
      - MYSQL_PASSWORD=koelpassword

volumes:
  db:
    driver: local
  covers:
    driver: local
  search_index:
    driver: local

Save the file by pressing Ctrl X and entering Y when prompted.

The above file launches containers based on Koel and MySQL’s docker images. It exposes Koel to port 8080 on your machine. The music and the environment file are mounted to the respective locations on the container. The directory for music covers and the search index, along with MySQL data, is mounted as local volumes. Choose a strong password for the variables MYSQL_ROOT_PASSWORD, MYSQL_PASSWORD and match those values with the variables for the Koel container in the file above. To link the Koel container with the database container, make sure the DB_HOST and depends_on variables are named after the Database container’s service name.

Step 7 – Start Koel Container

Launch the Koel Container using the following command.

$ docker-compose up -d

Initialize Koel for the first time

Log in to the Koel Container shell. koel in the command below refers to the name of the container set via the container_name variable in the Docker compose file above. If you don’t have a container name set, you will have to find the name of the container first and use that in the following command.

$ docker exec --user www-data -it koel bash

Run the following command to create an administrator account and initialize the database.

$ php artisan koel:init --no-assets

Change Administrator Password

Koel creates a default administrator account with the following credentials.

email: [email protected]
password: KoelIsCool

You can change the password for the administrator account using the following command from inside the container shell.

$ php artisan koel:admin:change-password

Exit the container shell.

$ exit

Step 8 – Install SSL

To install an SSL certificate using Let’s Encrypt, we need to install the Certbot tool.

Firstly, you need to download and install the EPEL repository.

$ sudo dnf install epel-release

Run the following commands to install Certbot.

$ sudo dnf install certbot

Generate the SSL certificate.

$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d koel.example.com

The above command will download a certificate to the /etc/letsencrypt/live/koel.example.com directory on your server.

Generate a Diffie-Hellman group certificate.

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

Create a challenge web root directory for Let’s Encrypt auto-renewal.

$ sudo mkdir -p /var/lib/letsencrypt

Create a Cron Job to renew the SSL. It will run every day to check the certificate and renew it if needed. For that, first, create the file /etc/cron.daily/certbot-renew and open it for editing.

$ sudo nano /etc/cron.daily/certbot-renew

Paste the following code.

#!/bin/sh
certbot renew --cert-name koel.example.com --webroot -w /var/lib/letsencrypt/ --post-hook "systemctl reload nginx"

Save the file by pressing Ctrl X and entering Y when prompted.

Change the permissions on the task file to make it executable.

$ sudo chmod  x /etc/cron.daily/certbot-renew

Step 9 – Install Nginx

We will be installing the latest version of Nginx. Create and open the file /etc/yum.repos.d/nginx.repo for editing.

$ sudo nano /etc/yum.repos.d/nginx.repo

Paste the following lines in it.

[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

Save the file by pressing Ctrl X and entering Y when prompted.

Install Nginx.

$ sudo dnf install nginx

Verify the installation.

$ nginx -v
nginx version: nginx/1.20.2

Enable and start the Nginx service.

$ sudo systemctl enable nginx --now

Create and open the file /etc/nginx/conf.d/koel.conf for editing.

$ sudo nano /etc/nginx/conf.d/koel.conf

Paste the following code in it.

# Redirect all non-encrypted to encrypted
server {
    listen 80;
    listen [::]:80;
    server_name koel.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    
    server_name koel.example.com;

    ssl_certificate     /etc/letsencrypt/live/koel.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/koel.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/koel.example.com/chain.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

    access_log /var/log/nginx/koel.example.com.access.log main;
    error_log  /var/log/nginx/koel.example.com.error.log;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Forwarded-Host $host;
        client_max_body_size 400M;
    	proxy_pass  http://localhost:8080;
    	proxy_http_version 1.1;
        proxy_set_header Host $host;
    }
}

Once finished, save the file by pressing Ctrl X and entering Y when prompted. The above configuration allows Nginx to act as a proxy server and bind to the port 8080 on localhost.

Open the file /etc/nginx/nginx.conf for editing.

$ sudo nano /etc/nginx/nginx.conf

Add the following line before the line include /etc/nginx/conf.d/*.conf;.

server_names_hash_bucket_size  64;

Save the file by pressing Ctrl X and entering Y when prompted.

Verify the Nginx configuration file syntax.

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Restart the Nginx service to enable the new configuration.

$ sudo systemctl restart nginx

Step 10 – Access Koel

You can access Koel by visiting the URL https://koel.example.com in your browser. You will be greeted by the following login screen.

<img alt="Koel Login Screen" data-ezsrc="https://kirelos.com/wp-content/uploads/2022/05/echo/koel_login_screen.png62792a6ee8ac5.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="477" loading="lazy" referrerpolicy="no-referrer" src="data:image/svg xml,” width=”464″>

Enter [email protected] as your username and the password you set before logging in. The following dashboard will appear on successful login.

<img alt="Koel Dashboard" data-ezsrc="https://kirelos.com/wp-content/uploads/2022/05/echo/koel_dashboard.png62792a6f2c69d.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="520" loading="lazy" referrerpolicy="no-referrer" src="data:image/svg xml,” width=”750″>

Step 11 – Import Music

Copy the music files you want to import to the ~/koel/music folder of your system. You can use the scp command to import the files from your local PC to the server.

$ scp test.mp3 [email protected]:/home/user/koel/music

Once you have copied the files to the ~/koel/music folder, run the following command to import the music into Koel.

$ docker exec --user www-data koel php artisan koel:sync

The music will show up in Koel’s web interface, and you can start playing.

Koel’s web interface also allows you to upload songs directly.

Step 12 – Update Koel

Switch to the Koel directory.

$ cd ~/koel

Pull the latest Koel Docker image.

$ docker-compose pull

Power down the container.

$ docker-compose down --remove-orphans

Start the container with updated images.

$ docker-compose up -d

Verify the Docker containers.

$ docker ps

Conclusion

This concludes the tutorial on installing Koel Music Streaming Service using Docker on a Rocky Linux server. If you have any questions, post them in the comments below.