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:
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:
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:
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:
Prüfe ihren Status:
Der erste Start kann etwas dauern. Zeige bei Problemen die letzten Protokollzeilen an:
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:
7. Dateien und Plugins sichern¶
Stoppe Kimai kurz, damit sich die Dateien während der Sicherung nicht ändern:
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:
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:
Stoppe die bisherigen Container:
Starte Kimai mit den neuen Images:
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
.enversetzt 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_HOSTSein und starte den Container neu. - Anmeldung klappt nicht: Verwende die Werte aus
ADMIN_EMAILundADMIN_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¶
- Offizielle Kimai-Docker-Compose-Anleitung
- Offizielle Kimai-Backup-Anleitung
- Video: Creating Self Hosted Kimai Time Tracking Server
- Video: Self Host Time Tracking with Kimai
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.