Zum Inhalt

Kimai-Zeiterfassung mit Docker installieren

Veröffentlicht am 22. August 2026 · Geschätzte Lesezeit: 4 Minuten

Kimai erfasst Arbeitszeiten nach Kunden, Projekten und Tätigkeiten. Die Weboberfläche eignet sich für einzelne Personen ebenso wie für kleine Teams, während Datenbank und Dateien auf deinem eigenen Server bleiben. Für die vollständige Einrichtung solltest du etwa 25 Minuten einplanen.

Voraussetzungen

  • Ein Server mit Docker und Docker Compose
  • Mindestens 1 GB freier Arbeitsspeicher
  • Ein freier TCP-Port 8001
  • Eine feste IP-Adresse oder ein lokaler DNS-Name für den Server

1. Projektordner anlegen

Führe diesen Befehl auf dem Docker-Server aus:

mkdir -p ~/kimai && cd ~/kimai

2. Zugangswerte vorbereiten

Lege im Projektordner eine Datei namens .env an. Ersetze alle Werte in spitzen Klammern durch eigene Angaben. Verwende für die beiden Datenbankpasswörter unterschiedliche lange Zufallswerte aus Ziffern und den Buchstaben a bis f, damit sie sicher in der Datenbank-URL funktionieren:

DATABASE_NAME=kimai
DATABASE_USER=kimaiuser
DATABASE_PASSWORD=<datenbank-passwort>
DATABASE_ROOT_PASSWORD=<root-datenbank-passwort>
ADMIN_EMAIL=<admin-email>
ADMIN_PASSWORD=<admin-passwort>
TRUSTED_HOSTS=<server-ip>
APP_SECRET=<langer-zufallswert>

<server-ip> ist die IP-Adresse oder der DNS-Name, über den du Kimai öffnest. Einen geeigneten Wert für <langer-zufallswert> erzeugst du auf dem Server mit diesem Befehl:

openssl rand -hex 32

Mit demselben Befehl kannst du auch die beiden Datenbankpasswörter erzeugen. Für <admin-passwort> verwendest du ein eigenes starkes Passwort aus deinem Passwortmanager.

Schütze danach die Datei:

chmod 600 .env

Keine Beispielpasswörter übernehmen

Die .env-Datei enthält das Administrator- und beide Datenbankpasswörter. Verwende keine Werte wie changeme und speichere die Datei nicht in einem öffentlichen Repository.

3. Compose-Datei anlegen

Lege im Ordner ~/kimai eine Datei namens compose.yaml mit diesem Inhalt an:

services:
  sqldb:
    image: mysql:8.3
    container_name: kimai-db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DATABASE_NAME}
      MYSQL_USER: ${DATABASE_USER}
      MYSQL_PASSWORD: ${DATABASE_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DATABASE_ROOT_PASSWORD}
    command: --default-storage-engine innodb
    volumes:
      - kimai-mysql:/var/lib/mysql
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin -p$${MYSQL_ROOT_PASSWORD} ping -h localhost --silent"]
      interval: 20s
      start_period: 30s
      timeout: 10s
      retries: 5

  kimai:
    image: kimai/kimai2:stable
    container_name: kimai
    restart: unless-stopped
    depends_on:
      sqldb:
        condition: service_healthy
        restart: true
    ports:
      - "8001:8001"
    environment:
      APP_SECRET: ${APP_SECRET}
      TRUSTED_HOSTS: ${TRUSTED_HOSTS}
      ADMINMAIL: ${ADMIN_EMAIL}
      ADMINPASS: ${ADMIN_PASSWORD}
      DATABASE_URL: mysql://${DATABASE_USER}:${DATABASE_PASSWORD}@sqldb/${DATABASE_NAME}?charset=utf8mb4&serverVersion=8.3.0
    volumes:
      - kimai-data:/opt/kimai/var/data
      - kimai-plugins:/opt/kimai/var/plugins

volumes:
  kimai-data:
    name: kimai-data
  kimai-plugins:
    name: kimai-plugins
  kimai-mysql:
    name: kimai-mysql

Die MySQL-Datenbank erhält keinen Host-Port. Die drei benannten Volumes speichern Datenbank, erzeugte Dateien und Plugins unabhängig von den Containern.

4. Kimai starten

Starte beide Container im Projektordner:

docker compose up -d

Prüfe ihren Status:

docker compose ps

Der erste Start kann etwas dauern. Zeige bei Problemen die letzten Protokollzeilen an:

docker compose logs --tail=100 kimai sqldb

5. Anmelden und Grunddaten anlegen

Öffne http://<server-ip>:8001 im Browser. Ersetze <server-ip> durch denselben Wert wie in TRUSTED_HOSTS. Melde dich mit der E-Mail-Adresse und dem Administratorpasswort aus .env an.

Lege anschließend in dieser Reihenfolge mindestens einen Kunden, ein Projekt und eine Tätigkeit an. Starte danach über den Zeitmesser einen kurzen Testeintrag und stoppe ihn wieder.

Öffentlicher Zugriff nur mit HTTPS

Port 8001 sollte nicht direkt aus dem Internet erreichbar sein. Verwende für externen Zugriff einen Reverse Proxy mit gültigem TLS-Zertifikat und beschränke die Anmeldung zusätzlich, wenn möglich.

6. Datenbank sichern

Der folgende Befehl wird im Projektordner ausgeführt. Er erstellt einen konsistenten MySQL-Dump, ohne das Passwort in den Beispielcode zu schreiben:

docker compose exec -T sqldb sh -c 'exec mysqldump --single-transaction -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' > kimai-db-$(date +%F-%H%M).sql

Prüfe anschließend, ob die Datei angelegt wurde:

ls -lh kimai-db-*.sql

7. Dateien und Plugins sichern

Stoppe Kimai kurz, damit sich die Dateien während der Sicherung nicht ändern:

docker compose stop kimai

Sichere das Daten-Volume:

docker run --rm -v kimai-data:/data:ro -v "$PWD:/backup" alpine sh -c 'tar czf /backup/kimai-data-$(date +%F-%H%M).tar.gz -C /data .'

Sichere danach installierte Plugins:

docker run --rm -v kimai-plugins:/data:ro -v "$PWD:/backup" alpine sh -c 'tar czf /backup/kimai-plugins-$(date +%F-%H%M).tar.gz -C /data .'

Starte Kimai wieder:

docker compose start kimai

Sichere zusätzlich compose.yaml und .env verschlüsselt auf einem anderen Gerät.

8. Aktualisieren und zurückgehen

Erstelle vor dem Update Datenbank- und Dateisicherungen. Lade anschließend neue Images:

docker compose pull

Stoppe die bisherigen Container:

docker compose down

Starte Kimai mit den neuen Images:

docker compose up -d

Teste Anmeldung und einen Zeiteintrag. Für eine Wiederherstellung verwendest du dieselbe Kimai-Version wie beim Backup, spielst den SQL-Dump in eine leere Datenbank ein und stellst Daten- sowie Plugin-Volume wieder her.

9. Typische Fehler beheben

  • Datenbank bleibt ungesund: Prüfe, ob alle Platzhalter in .env ersetzt wurden und die Passwörter keine Zeilenumbrüche enthalten.
  • Kimai meldet einen nicht vertrauenswürdigen Host: Trage die tatsächlich verwendete IP-Adresse oder Domain in TRUSTED_HOSTS ein und starte den Container neu.
  • Anmeldung klappt nicht: Verwende die Werte aus ADMIN_EMAIL und ADMIN_PASSWORD; die Variablen legen den ersten Administrator an.
  • Port 8001 ist belegt: Ändere links in "8001:8001" den Host-Port und passe die Browseradresse an.
  • Nach der Wiederherstellung treten Fehler auf: Prüfe, ob Kimai-Version, Plugins und Datenbankschema zum Backup passen.

10. Quellen und Videos

Fertig

Kimai läuft nun unter http://<server-ip>:8001 und speichert Zeiten dauerhaft in MySQL. Lege einen kurzen Testeintrag für einen Kunden und ein Projekt an. Erscheint er nach einer Neuanmeldung weiterhin in der Zeiterfassung, funktioniert die Installation.