Direkt zum Hauptinhalt

Installation via Docker

Beschreibung

Kimai via Docker mit https via Letsencrypt.


Installation

Vorbereitung

Als erstes erstellen wir unsere Verzeichnisse

mkdir -p /root/kimai/mariadb
mkdir -p /root/kimai/data

Nun erstellen wir im Verzeichnis /root/kimai eine neue Datei namens .env

nano /root/kimai/.env

Inhalt:

# MySQL Credentials
MYSQL_ROOT_PASSWORD=12345678
MYSQL_USER=kimai
MYSQL_PASSWORD=1234567890
MYSQL_DATABASE=kimai

# Volume directories
MARIADB_VOLUME_DIR=/root/kimai/mariadb
DATA_VOLUME_DIR=/root/kimai/data

# Domain and email for Let's Encrypt
DOMAIN_NAME=ihredomain.de
LETSENCRYPT_EMAIL=ihre-email@beispiel.de


Docker-compose Datei erstellen

nano /root/kimai/docker-compose.yml

Inhalt

version: '3.3'

services:
  mariadb:
    image: mariadb:latest
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
    volumes:
      - ${MARIADB_VOLUME_DIR}:/var/lib/mysql

  kimai:
    image: kimai/kimai2:fpm-alpine-1.14-prod
    restart: unless-stopped
    environment:
      - DATABASE_URL=mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@mariadb/${MYSQL_DATABASE}
    volumes:
      - ${DATA_VOLUME_DIR}:/opt/kimai/var

  webserver:
    image: nginx:alpine
    restart: unless-stopped
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ${DATA_VOLUME_DIR}:/opt/kimai/var
      - ./certbot-etc:/etc/letsencrypt
      - ./certbot-www:/var/www/certbot
      - ./certbot-log:/var/log/letsencrypt
      - ./nginx-log:/var/log/nginx
    ports:
      - "80:80"
      - "443:443"

  certbot:
    image: certbot/certbot
    volumes:
      - ./certbot-etc:/etc/letsencrypt
      - ./certbot-www:/var/www/certbot
      - ./certbot-log:/var/log/letsencrypt
    entrypoint: '/bin/sh -c'
volumes:
  mariadb_data:
  kimai_data:
  certbot-etc:
  certbot-www:

Nun sicher stellen das die ports 80 und 443 auch über die Domain auf den Server ereichbar sind.

hier ein kleines script das auf den port 80 lauscht um dies zu testen

nano /root/kimai/testeweb.sh

Inhalt

#!/bin/bash

# Funktion, die aufgerufen wird, wenn das Skript ein SIGINT-Signal (Ctrl+C) empfängt
cleanup() {
    echo "Server wird beendet..."
    exit 0
}

# Trap für das SIGINT-Signal einrichten
trap cleanup SIGINT

# Endlosschleife für den Server
while true; do
    # Listen on port 80
    { echo -ne "HTTP/1.1 200 OK\r\nContent-Length: $(echo -n "Hello, World!" | wc -c)\r\n\r\nHello, World!"; } | nc -l -p 80 -q 1
done

Danach ausführbar machen

chmod +x /root/kimai/testeweb.sh

nun das Script starten, kann mit strg+c wieder abgebrochen werden.
Nun kann getestet werden ob Firewall/Portforwarding richtig funktioniert, idem in einem Webbrowser die public ip aufegrufen wird.
Es muss eine hello World Seite zurück gegben werden.


Nun das Init shell script erstellen was die cert Verzeichnisse und die nginx.conf erstellt.
Das programm holt sich den cert Pfad aus der docker-compose datei. Denn der certbot wird mit docker compose im Shellscript gestartet.
jetzt muss nur noch sichergestellt werden das der Domainname auf die ip zeigt

nano /root/kimai/setup.sh


Hinweis: um das Cert erstmal zu testen kann der Befehl auch mit dry run erweitert werden im script.

docker-compose run --rm --entrypoint "" certbot certbot certonly --dry-run --webroot --webroot-path=/var/www/certbot \
    --email ${LETSENCRYPT_EMAIL} --agree-tos --no-eff-email \
    --domain ${DOMAIN_NAME} --rsa-key-size 4096



Inhalt

#!/bin/bash

# Laden der Umgebungsvariablen aus der .env-Datei
if [ -f .env ]; then
    export $(grep -v '^#' .env | xargs)
else
    echo ".env-Datei nicht gefunden!"
    exit 1
fi

# Überprüfen, ob DOMAIN_NAME und LETSENCRYPT_EMAIL gesetzt sind
if [ -z "$DOMAIN_NAME" ] || [ -z "$LETSENCRYPT_EMAIL" ]; then
    echo "DOMAIN_NAME und/oder LETSENCRYPT_EMAIL sind in der .env-Datei nicht gesetzt!"
    exit 1
fi

# Erstellen der benötigten Verzeichnisse
mkdir -p ./certbot-etc
mkdir -p ./certbot-www
mkdir -p ./certbot-log
mkdir -p ./nginx-log

# Erstellen der Nginx-Konfigurationsdatei für den ersten Lauf (ohne SSL)
cat << EOF > ./nginx.conf
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '\$remote_addr - \$remote_user [\$time_local] "\$request" '
                      '\$status \$body_bytes_sent "\$http_referer" '
                      '"\$http_user_agent" "\$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    server {
        listen 80;
        server_name ${DOMAIN_NAME};

        location /.well-known/acme-challenge/ {
            root /var/www/certbot;
            try_files \$uri =404;
        }
    }
}
EOF

# Starten des Webserver-Containers (erster Lauf ohne SSL)
echo "Starte Webserver-Container..."
docker-compose down
docker-compose up -d webserver

# Warten, um sicherzustellen, dass Nginx vollständig gestartet ist
echo "Warte auf Webserver..."
sleep 5

# Ausführen des Certbot für den ersten Lauf
echo "Starte Certbot..."
docker-compose run --rm --entrypoint "" certbot certbot certonly --webroot --webroot-path=/var/www/certbot \
    --email ${LETSENCRYPT_EMAIL} --agree-tos --no-eff-email \
    --domain ${DOMAIN_NAME} --rsa-key-size 4096

# Aktualisieren Sie die Nginx-Konfigurationsdatei, um SSL zu aktivieren
cat << EOF > ./nginx.conf
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '\$remote_addr - \$remote_user [\$time_local] "\$request" '
                      '\$status \$body_bytes_sent "\$http_referer" '
                      '"\$http_user_agent" "\$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    server {
        listen 80;
        server_name ${DOMAIN_NAME};

        location /.well-known/acme-challenge/ {
            root /var/www/certbot;
            try_files \$uri =404;
        }

        location / {
            return 301 https://\$host\$request_uri;
        }
    }

    server {
        listen 443 ssl;
        server_name ${DOMAIN_NAME};

        ssl_certificate /etc/letsencrypt/live/${DOMAIN_NAME}/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/${DOMAIN_NAME}/privkey.pem;

        location / {
            proxy_pass http://kimai:8001;
            proxy_set_header Host \$host;
            proxy_set_header X-Real-IP \$remote_addr;
            proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto \$scheme;
            client_max_body_size 100M;
        }
    }
}
EOF

# Starten Sie den Webserver-Container neu, um die aktualisierte Konfiguration zu verwenden
echo "Starte Webserver-Container neu..."
docker-compose down
docker-compose up -d webserver

echo "Setup abgeschlossen. Bitte überprüfen und anpassen Sie die nginx.conf entsprechend."

Das script ausführbar machen

chmod +x /root/kimai/setup.sh

Docker installieren, env anpassen Webcheck und Container starten

apt install docker.io docker-compose

Nun die .env Datei wenn nicht schon geschenen, an die eigenen Bedüfnisse anpassen.
Dann das setup.sh script ausführen.


Container Starten

Ins kimai Verzeichnis gehen

cd /root/kimai

Nun

docker-compose up 

ausführen, dort gibts dann die consolen ausgabe.

Wenn alles läuft und initialisiert ist den Container mit

 docker-compose down

wieder stoppen und dann als Daemon mit

 docker-compose up -d 


wieder starten

Benutzer anlegen


Die Rollen
Role name Description
User Normal user can track their working times, see basic reports and change their own preferences. Technical name: ROLE_USER
Teamlead Manages teams with permissions for invoices and access to all team timesheets. Technical name: ROLE_TEAMLEAD
Administrator Can manage all content and timesheet related data, but lack user administration and system privileges. Technical name: ROLE_ADMIN
System-Admin Has permissions to manage everything in Kimai, from content to timesheets to users, plugins and system configurations. Technical name: ROLE_SUPER_ADMIN
die container id mit docker ps herausfinden

docker exec -ti <containerid> \
         /opt/kimai/bin/console kimai:user:create <username> <emailadresse> ROLE_SUPER_ADMIN

Beispiel:

docker exec -ti 32da986c57c2 \
         /opt/kimai/bin/console kimai:user:create admin admin@example.com ROLE_SUPER_ADMIN
         
Dann kann ein Kennwort vergeben werden. Muss mindestens 8 Zeichen haben



Autostart

Ein script das im Verzeichnis liegen muss wo die .env und die docker-compose.yml liegen

nano /root/kimai/createrenewservice.sh


Inhalt

#!/bin/bash

# Ermitteln des Verzeichnisses, in dem dieses Skript liegt
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

# Pfade zu .env und docker-compose.yml Dateien
ENV_PATH="$SCRIPT_DIR/.env"
DOCKER_COMPOSE_PATH="$SCRIPT_DIR/docker-compose.yml"

# Lesen der .env-Datei
if [ -f "$ENV_PATH" ]; then
    export $(grep -v '^#' "$ENV_PATH" | xargs)
else
    echo "$ENV_PATH nicht gefunden!"
    exit 1
fi

# Erstellen der systemd-Service-Datei
cat << EOF |tee /etc/systemd/system/certbot-renew.service
[Unit]
Description=Certbot Renewal

[Service]
Type=oneshot
ExecStart=/usr/bin/docker-compose -f $DOCKER_COMPOSE_PATH run --rm --entrypoint "" certbot certbot renew --quiet --deploy-hook "docker-compose exec webserver nginx -s reload"
Environment=LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
Environment=DOMAIN_NAME=${DOMAIN_NAME}

[Install]
WantedBy=multi-user.target
EOF

# Erstellen der systemd-Timer-Datei
cat << EOF | tee /etc/systemd/system/certbot-renew.timer
[Unit]
Description=Timer for Certbot Renewal

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target
EOF

# Aktivieren und Starten des systemd-Dienstes und Timers
systemctl enable certbot-renew.service
systemctl start certbot-renew.service
systemctl enable certbot-renew.timer
systemctl start certbot-renew.timer

echo "Certbot systemd Dienst und Timer wurden eingerichtet."

Danach das script, ausführbar machen

chmod +x createrenewservice.sh

Nun ausführen

./createrenewservice.sh

Nun den Dienst testen

systemctl start certbot-renew.service

Status des Timers überpüfen

systemctl list-timers

Ausgabe

NEXT                        LEFT          LAST                        PASSED UNIT                         ACTIVATES
Wed 2024-01-03 18:33:24 CET 2h 56min left Wed 2024-01-03 09:08:28 CET 6h ago apt-daily.timer              apt-daily.se>
Thu 2024-01-04 00:00:00 CET 8h left       n/a                         n/a    certbot-renew.timer          certbot-rene>
Thu 2024-01-04 00:00:00 CET 8h left       Wed 2024-01-03 08:12:38 CET 7h ago logrotate.timer              logrotate.se>
Thu 2024-01-04 00:00:00 CET 8h left       Wed 2024-01-03 08:12:38 CET 7h ago man-db.timer                 man-db.servi>
Thu 2024-01-04 06:32:46 CET 14h left      Wed 2024-01-03 08:31:44 CET 7h ago apt-daily-upgrade.timer      apt-daily-up>
Thu 2024-01-04 08:30:32 CET 16h left      Wed 2024-01-03 08:30:32 CET 7h ago systemd-tmpfiles-clean.timer systemd-tmpf>
Sun 2024-01-07 03:10:39 CET 3 days left   Wed 2024-01-03 08:13:10 CET 7h ago e2scrub_all.timer            e2scrub_all.>
Mon 2024-01-08 00:14:39 CET 4 days left   Wed 2024-01-03 09:08:29 CET 6h ago fstrim.timer                 fstrim.servi>


...
Thu 2024-01-04 00:00:00 CET 8h left       n/a                         n/a    certbot-renew.timer 
...

noch 8 Stunden verbleibend... Timer ist aktiv


Überpüfen on das Zertifikat erneuert wurde.