Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Cloud / Hosting 05.07.2026 · 11 min Lesezeit

Koel mit Docker installieren: Schlanker persönlicher Musik-Streamingserver

Koel ist mit 17.000+ Stars der eleganteste selbst gehostete Musik-Streamingserver: Laravel-Backend, Vue.js-Frontend, Smart Playlists und Last.fm-Scrobbling – kostenlos. Diese Anleitung zeigt, wie du Koel per Docker Compose in 20 Minuten startest.

Koel mit Docker installieren: Moderne Oberfläche eines selbst gehosteten Musik Streaming Servers mit Docker Container, Linux Server, Terminal und Weboberfläche für die private Musikbibliothek im Self Hosting.

Spotify und Apple Music sind bequem – aber sie kennen jeden Song, den du hörst, und du zahlst monatlich für Musik, die dir nicht gehört. Koel dreht dieses Modell um: Du betreibst den Server selbst, deine MP3- und FLAC-Dateien bleiben auf deiner eigenen Hardware, und das Interface sieht dabei besser aus als die meisten kommerziellen Alternativen. Das Laravel-PHP-Backend kombiniert sich mit einem Vue.js/TypeScript-Frontend zu einer Streaming-App, die Smart Playlists, Last.fm-Scrobbling, Podcast-Import und sogar einen KI-Assistenten für Sprachbefehle mitbringt – alles in der kostenlosen Community-Edition. Mit 17.200 GitHub-Stars und über 160 Releases ist Koel aktiv gepflegt und produktionsreif. Diese Anleitung richtet sich an alle, die eine datenschutzfreundliche Spotify-Alternative für die eigene Musiksammlung auf einem Linux-Host, einer VM oder einem NAS mit Docker betreiben möchten.

Voraussetzungen

  1. Docker Engine 24+ und das Docker Compose Plugin v2 (docker compose ohne Bindestrich) sind auf dem Host installiert – wie das geht, erklärt die Grundanleitung Docker und Docker Compose auf Linux installieren.
  2. Linux-Host, VM oder NAS mit Docker-Unterstützung (Ubuntu, Debian, Raspberry Pi OS, etc.) – auch linux/arm64 und linux/arm/v7 werden vom Multi-Arch-Image abgedeckt.
  3. Mindestens 1 GB RAM (2 GB empfohlen bei größeren Bibliotheken); mindestens 10 GB freier Speicher für Images, Datenbank und Suchindex.
  4. Eine Musiksammlung als MP3-, FLAC-, AAC-, OGG- oder WAV-Dateien auf dem Host.
  5. Optional: Domain oder feste IP für externen Zugriff; für HTTPS einen vorgeschalteten Reverse Proxy (Caddy, Traefik oder Nginx) – Koel selbst liefert kein TLS.

Schritt 1: Projektordner anlegen und Eckdaten überblicken

Leg zunächst ein sauberes Verzeichnis für den Koel-Stack an. Alle Compose-Dateien und Secrets landen hier, und du behältst den Überblick beim späteren Update.

sudo mkdir -p /opt/koel
cd /opt/koel

Hier die wichtigsten technischen Eckdaten auf einen Blick:

EigenschaftWert
Imagephanan/koel:latest (aktuell v9.8.0)
RegistrierungDocker Hub (hub.docker.com/r/phanan/koel)
Architekturenlinux/amd64, linux/arm64, linux/arm/v7
Image-Größe~409 MB (amd64), ~386 MB (arm64)
Webinterface-Port80 (HTTP, kein TLS im Container)
Empfohlene DatenbankMariaDB 10.11
LizenzMIT (Community Edition kostenlos)
VolumeZweck
./music:/musicDeine Musikdateien (Host-Pfad einbinden)
koel_imagesAlbum-Cover und Avatare (persistent)
koel_searchSuchindex (sonst Neuaufbau nach Neustart)
koel_dbMariaDB-Datenbankdaten

Verifizieren: Das Verzeichnis existiert und ist leer.

ls /opt/koel
# Erwartet: leeres Verzeichnis (keine Fehlermeldung)

Schritt 2: .env-Datei mit Secrets anlegen

Secrets gehören nie direkt in die compose.yaml. Leg eine .env-Datei an, die Docker Compose automatisch einliest. Ersetze die Platzhalterwerte durch sichere, zufällige Passwörter – mindestens 20 Zeichen, gemischt.

# /opt/koel/.env

# Datenbank-Passwörter (bitte durch sichere Werte ersetzen!)
DB_PASSWORD=SICHERES_PASSWORT_HIER
DB_ROOT_PASSWORD=ROOT_PASSWORT_HIER

# Öffentliche URL der Koel-Instanz
APP_URL=http://192.168.1.100

# APP_KEY: Leer lassen – wird beim ersten Start automatisch generiert.
# Nach dem ersten Start auslesen und hier dauerhaft eintragen!
APP_KEY=

# HTTPS hinter Reverse Proxy?
FORCE_HTTPS=false

# Optional: Last.fm-Scrobbling
# LASTFM_API_KEY=dein_api_key
# LASTFM_API_SECRET=dein_api_secret

# Optional: Spotify Cover-Bilder
# SPOTIFY_CLIENT_ID=deine_client_id
# SPOTIFY_CLIENT_SECRET=dein_client_secret

Schränke die Dateiberechtigung direkt ein, damit andere Benutzer die Passwörter nicht lesen können:

chmod 600 /opt/koel/.env

Verifizieren: Die Datei ist angelegt und nur für den eigenen Benutzer lesbar.

ls -la /opt/koel/.env
# Erwartet: -rw------- 1 root root ... .env

Schritt 3: compose.yaml erstellen

Die folgende compose.yaml definiert zwei Services: den Koel-Applikationscontainer und MariaDB 10.11 als Datenbank. Ein Healthcheck stellt sicher, dass Koel erst startet, nachdem MariaDB vollständig bereit ist – ohne diesen Mechanismus schlägt der erste Start regelmäßig fehl.

# /opt/koel/compose.yaml
services:
  koel:
    image: phanan/koel:latest
    container_name: koel
    restart: unless-stopped
    depends_on:
      database:
        condition: service_healthy
    ports:
      - "80:80"
    environment:
      - DB_CONNECTION=mysql
      - DB_HOST=database
      - DB_PORT=3306
      - DB_USERNAME=koel
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_DATABASE=koel
      - APP_URL=${APP_URL:-http://localhost}
      - APP_KEY=${APP_KEY}
      - FORCE_HTTPS=${FORCE_HTTPS:-false}
      - MEMORY_LIMIT=512
      - SCAN_JOBS=4
      # Optional: Last.fm Scrobbling
      # - LASTFM_API_KEY=${LASTFM_API_KEY}
      # - LASTFM_API_SECRET=${LASTFM_API_SECRET}
      # Optional: Spotify Cover-Bilder
      # - SPOTIFY_CLIENT_ID=${SPOTIFY_CLIENT_ID}
      # - SPOTIFY_CLIENT_SECRET=${SPOTIFY_CLIENT_SECRET}
    volumes:
      - ./music:/music
      - koel_images:/var/www/html/storage/app/public/images
      - koel_search:/var/www/html/storage/search-indexes

  database:
    image: mariadb:10.11
    container_name: koel_db
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
      - MYSQL_DATABASE=koel
      - MYSQL_USER=koel
      - MYSQL_PASSWORD=${DB_PASSWORD}
    volumes:
      - koel_db:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--su-mysql", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s

volumes:
  koel_db:
    driver: local
  koel_images:
    driver: local
  koel_search:
    driver: local

Ein Hinweis zum Music-Volume: Das Verzeichnis ./music wird relativ zum Compose-Verzeichnis eingebunden. Du kannst stattdessen einen absoluten Pfad zu deiner bestehenden Musiksammlung angeben, z. B. /mnt/nas/musik:/music:ro (mit :ro für Read-Only, wenn Koel nichts schreiben soll).

Verifizieren: Die Syntax der Compose-Datei ist fehlerfrei.

docker compose config
# Erwartet: Fehlerfreie Ausgabe der gemergten Konfiguration ohne Warnungen

Schritt 4: Stack starten und APP_KEY dauerhaft sichern

Jetzt startest du den Stack. Beim ersten Start lädt Docker die Images (~409 MB), initialisiert MariaDB und führt die Laravel-Datenbankmigrationen aus. Das dauert je nach Verbindung 1–3 Minuten.

docker compose up -d

Beobachte die Logs, bis Koel vollständig gestartet ist:

docker compose logs -f koel

Warte, bis du in den Logs eine Zeile siehst wie Apache ... configured -- resuming normal operations oder den Hinweis, dass die Datenbankmigrationen abgeschlossen sind. Dann kannst du den Log-Stream mit Strg+C beenden.

Jetzt kommt der wichtigste Schritt: den generierten APP_KEY dauerhaft sichern. Wird er nicht gespeichert, generiert Koel bei jedem Neustart einen neuen Schlüssel – alle bestehenden Sessions werden ungültig und verschlüsselte Daten sind verloren.

docker exec koel php artisan key:generate --show
# Ausgabe: base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=

Kopiere den ausgegebenen Schlüssel (einschließlich base64:) und trage ihn in der .env-Datei ein:

APP_KEY=base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=

Damit der neue Wert aktiv wird, starte den Koel-Container neu:

docker compose up -d koel

Verifizieren: Beide Container laufen, MariaDB ist gesund, und der HTTP-Endpunkt antwortet.

docker compose ps
# Erwartet:
# NAME       IMAGE                STATUS                  PORTS
# koel       phanan/koel:latest   Up X minutes            0.0.0.0:80->80/tcp
# koel_db    mariadb:10.11        Up X minutes (healthy)

curl -I http://localhost
# Erwartet: HTTP/1.1 200 OK oder 302 Found

Schritt 5: Ersteinrichtung im Browser und Passwort ändern

Öffne http://<server-ip> im Browser. Du siehst den Koel-Login. Die Standard-Zugangsdaten lauten:

  1. E-Mail: admin@koel.dev
  2. Passwort: KoelIsCool

Diese Kombination ist öffentlich bekannt und muss sofort geändert werden. Ändere das Admin-Passwort über die Kommandozeile:

docker exec -it koel php artisan koel:admin:change-password

Der Befehl fragt dich interaktiv nach einer neuen E-Mail-Adresse und einem neuen Passwort. Wähle ein starkes Passwort mit mindestens 16 Zeichen.

Verifizieren: Der Login mit dem neuen Passwort funktioniert. Das Interface zeigt ein leeres Dashboard – das ist korrekt, da die Bibliothek noch nicht gescannt wurde.

Schritt 6: Musikbibliothek einbinden und scannen

Koel erwartet die Musikdateien unter /music im Container. Du hast den Pfad bereits in der compose.yaml als Host-Mount definiert. Falls du ein separates Verzeichnis verwenden möchtest, passe den linken Teil des Volume-Eintrags an und starte den Stack neu.

Koel scannt die Bibliothek nicht automatisch. Der erste manuelle Scan ist Pflicht, und bei neuen Dateien muss er wiederholt werden:

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

Wichtig: Der Befehl muss mit --user www-data ausgeführt werden, sonst entstehen Berechtigungsprobleme im Storage-Verzeichnis. Bei großen Bibliotheken (über 10.000 Titel) kann der erste Scan mehrere Minuten dauern und spürbar CPU sowie RAM beanspruchen. Du kannst den Scan mit MEMORY_LIMIT=1024 und SCAN_JOBS=8 beschleunigen, falls genug RAM vorhanden ist.

Für automatisches Scanning bei neuen Dateien richtest du einen Cron-Job auf dem Host ein:

# crontab -e (als root)
*/30 * * * * docker exec --user www-data koel php artisan koel:sync >> /var/log/koel-sync.log 2>&1

Verifizieren: Nach dem Scan erscheinen deine Songs, Alben und Künstler in der Koel-Oberfläche. Prüfe die Scan-Ausgabe auf Fehler:

docker compose logs koel | tail -20
# Erwartet: Keine PHP-Fehlermeldungen; Sync-Ergebnis zeigt Anzahl neu gefundener Tracks

Schritt 7: HTTPS über Reverse Proxy einrichten (empfohlen)

Koel selbst liefert kein TLS. Für den Zugriff über das Internet oder aus Sicherheitsgründen im Heimnetz ist ein vorgeschalteter Reverse Proxy Pflicht. Eine vollständige Anleitung findest du unter Caddy als Reverse Proxy mit automatischem HTTPS einrichten.

In der Koel-.env trägst du dann ein:

APP_URL=https://musik.deine-domain.de
FORCE_HTTPS=true

Passe außerdem das Port-Mapping in der compose.yaml an, wenn der Reverse Proxy auf demselben Host läuft – dann ist Koel nur intern erreichbar:

    ports:
      - "127.0.0.1:8080:80"

Starte danach den Stack neu:

docker compose up -d

Verifizieren: Der Browser zeigt das Schloss-Symbol, und Koel lädt alle Assets über HTTPS ohne Mixed-Content-Warnungen in der Browser-Konsole.

Schritt 8: Updates und Backup

Koel und MariaDB werden mit zwei Befehlen aktualisiert:

cd /opt/koel
docker compose pull
docker compose up -d

Nach einem Update führt Koel beim Start automatisch ausstehende Datenbankmigrationen aus – kein manueller Eingriff nötig, solange SKIP_INIT=false (Standard) gesetzt ist.

Für ein vollständiges Backup sicherst du drei Dinge:

  1. Die .env-Datei (enthält APP_KEY und Passwörter – verschlüsselt aufbewahren!)
  2. Den MariaDB-Dump: docker exec koel_db mariadb-dump -u koel -p<DB_PASSWORD> koel > koel_backup.sql
  3. Das Volume koel_images (Album-Cover): docker run --rm -v koel_images:/data -v $(pwd):/backup alpine tar czf /backup/koel_images.tar.gz /data

Die Musikdateien selbst sicherst du separat als Teil deiner normalen Backup-Strategie – eine Anleitung bietet 3-2-1-Backup-Strategie umsetzen.

Verifizieren: Nach dem Update laufen beide Container, und die Weboberfläche ist erreichbar.

docker compose ps
# Erwartet: beide Container mit Status "Up" und koel_db "(healthy)"

Troubleshooting / Typische Fehler

  1. SQLSTATE[HY000] [2002] Connection refused: Koel startete, bevor MariaDB bereit war. Ursache ist ein fehlendes oder zu kurzes Healthcheck-start_period. Stelle sicher, dass depends_on mit condition: service_healthy gesetzt ist. Mit docker compose restart koel erzwingst du einen erneuten Startversuch.
  2. Port 80 bereits belegt (bind: address already in use): Auf dem Host läuft bereits ein Webserver. Ändere das Port-Mapping in der compose.yaml auf einen freien Port, z. B. "8080:80", dann docker compose up -d.
  3. Musik nach dem Scan nicht sichtbar: Der Scan wurde nicht mit --user www-data ausgeführt oder das /music-Verzeichnis ist für den Container nicht lesbar (UID 33 = www-data). Fix: chmod o+rx /pfad/zur/musik auf dem Host, dann Scan wiederholen.
  4. Mixed-Content-Fehler im Browser: Koel läuft hinter HTTPS-Proxy, aber FORCE_HTTPS=true ist nicht gesetzt. Laravel generiert interne HTTP-URLs. Fix: FORCE_HTTPS=true in die .env eintragen und docker compose up -d ausführen.
  5. Sessions nach Neustart ungültig: APP_KEY wurde nicht dauerhaft in der .env gespeichert. Koel generierte einen neuen Schlüssel. Fix: docker exec koel php artisan key:generate --show, Ausgabe in .env eintragen, Container neu starten.
  6. Standard-Passwort nicht geändert: admin@koel.dev / KoelIsCool ist öffentlich bekannt. Sofort ausführen: docker exec -it koel php artisan koel:admin:change-password.
  7. Hohe CPU-Last beim ersten Scan: Normales Verhalten bei großen Bibliotheken. Reduziere SCAN_JOBS=2 in der Umgebung, um die Last zu begrenzen, oder starte den Scan zu einem Zeitpunkt geringer Auslastung.
  8. MariaDB 11.x statt 10.11: Neuere MariaDB-Versionen können SQL-Kompatibilitätsprobleme verursachen. Bleibe bei mariadb:10.11, bis eine offizielle Freigabe für höhere Versionen vorliegt.

Häufige Fragen

Welche Audioformate unterstützt Koel?

Koel unterstützt alle gängigen Formate: MP3, FLAC, AAC, OGG, WAV und WMA. FLAC wird standardmäßig per ffmpeg zu MP3 mit 128 kbps transcodiert (TRANSCODE_FLAC=true). ffmpeg ist bereits im Container enthalten. Die Bitrate lässt sich mit TRANSCODE_BIT_RATE=320 erhöhen.

Funktioniert Koel auf einem Raspberry Pi?

Ja. Das offizielle Image phanan/koel ist Multi-Arch und unterstützt linux/arm64 und linux/arm/v7. Ein Raspberry Pi 4 oder 5 mit 4 GB RAM betreibt Koel problemlos. Auf einem Pi 3 mit 1 GB RAM ist der Betrieb knapp möglich – MEMORY_LIMIT=256 und SCAN_JOBS=1 empfehlen sich dann.

Was ist der Unterschied zwischen Community Edition und Koel Plus?

Die kostenlose Community Edition (MIT-Lizenz) bietet den vollen Funktionsumfang für einen Benutzer: Smart Playlists, Last.fm-Scrobbling, Podcasts, KI-Assistent, Spotify- und MusicBrainz-Metadaten sowie YouTube-Integration. Koel Plus (Abonnement) schaltet Multi-User-Bibliotheken, Single Sign-On (Google, OIDC), Cloud-Storage-Treiber (S3, Dropbox, SFTP, WebDAV), eigene Themes und White-Labeling frei. Für den persönlichen Heimgebrauch reicht die kostenlose Edition vollständig aus.

Wie richte ich Last.fm-Scrobbling ein?

Du benötigst eine Last.fm-Developer-App (unter last.fm/api/account/create). Trage API Key und Shared Secret in der .env ein, kommentiere die entsprechenden Zeilen in der compose.yaml aus und starte den Container neu. Die Verknüpfung mit dem eigenen Last.fm-Account erfolgt dann in den Koel-Benutzereinstellungen im Browser.

Wie aktualisiere ich die Bibliothek automatisch bei neuen Dateien?

Richte einen Cron-Job auf dem Host ein, der docker exec --user www-data koel php artisan koel:sync in regelmäßigen Abständen aufruft. Alternativ kann ein inotifywait-basierter Watcher Änderungen im Musikverzeichnis überwachen und den Scan nur bei tatsächlichen Dateiänderungen auslösen – das spart Ressourcen bei sehr großen Bibliotheken.

Kann ich statt MariaDB PostgreSQL verwenden?

Ja. Tausche den database-Service gegen postgres:16 aus, setze DB_CONNECTION=pgsql und DB_PORT=5432 und verwende die PostgreSQL-Umgebungsvariablen (POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD). Das offizielle Docker-Repository unter github.com/koel/docker bietet ein fertiges docker-compose.postgres.yml-Beispiel.

Fazit

Koel ist eine der elegantesten Self-Hosting-Lösungen überhaupt: Das Interface übertrifft viele kommerzielle Dienste, der Funktionsumfang der kostenlosen Edition ist beeindruckend, und der Docker-Betrieb ist dank des offiziellen Multi-Arch-Images unkompliziert. Der einzige Stolperstein, der in der Praxis immer wieder auftaucht, ist der APP_KEY: Ihn direkt nach dem ersten Start dauerhaft in der .env zu sichern ist der wichtigste Schritt. Wer Koel produktiv betreiben möchte, kombiniert ihn mit einem Reverse Proxy für HTTPS, einem Cron-Job für den automatischen Bibliotheksscan und einem regelmäßigen Datenbank-Dump – dann läuft die persönliche Spotify-Alternative stabil und wartungsarm. Für ein sauber abgesichertes Docker-Setup lohnt sich außerdem ein Blick auf Docker Compose absichern: Secrets, Healthchecks und Non-Root.

Weiterführende Anleitungen und Quellen

  1. Caddy als Reverse Proxy mit automatischem HTTPS einrichten
  2. Docker Compose absichern: Secrets, Healthchecks und Non-Root
  3. 3-2-1-Backup-Strategie umsetzen: Anleitung mit Restic, USB-Disk und S3-Cloud
  4. Jellyfin mit Docker: eigener Media-Server ohne Abo

Offizielle Quellen: Koel Docker Repository (koel/docker) – die maßgebliche Referenz für alle Docker-Deployments, mit fertigen Compose-Beispielen für MySQL und PostgreSQL. Die allgemeine Koel-Dokumentation unter docs.koel.dev verweist für Docker-Details explizit auf dieses separate Repository.

Passende Anleitungen auf S-EDV

  1. GPT-5.5-Cyber: OpenAI startet Sicherheitsmodell als Konkurrenz zu Anthropic Myth
  2. Android 17: Google rollt Pixel Drop mit neuen Funktionen und Sicherheitspatches
  3. netcup Local Block Storage bestellen, einrichten und unter Linux einbinden