Zum Inhalt springen

Installation

Sie installieren heinzelhaus auf einem eigenen Server, entweder mit einem Skript auf einem Proxmox-Host oder mit dem Installationsskript auf einem Debian- oder Ubuntu-Server. Beide Wege richten Docker, die Konfiguration und alle Dienste ein. Am Ende öffnen Sie die Adresse im Browser und legen das erste Administratorkonto an.

Damit heinzelhaus auf Ihrem Server läuft und Ihre Mitarbeitenden es im Browser öffnen können.

Sie brauchen: root-Zugang zum Server oder zum Proxmox-Host, einen Server nach den Systemvoraussetzungen und den Zugang zum Programmstand (siehe unten).

Haben Sie heinzelhaus schon vor Version 1.0 unter dem Namen CasaTastic eingerichtet? Dann installieren Sie nicht neu, sondern ziehen einmalig um: Umzug von CasaTastic auf heinzelhaus.

Weg Wann Was Sie tun
A: Proxmox Sie betreiben einen Proxmox-Host und möchten heinzelhaus in einem eigenen Container Auf dem Proxmox-Host ein Skript laden und ausführen. Es legt den Container an und installiert darin alles.
B: Server oder virtuelle Maschine Debian oder Ubuntu läuft bereits, als eigener Rechner, virtuelle Maschine oder bei einem Cloud-Anbieter Programmstand mit git holen und install.sh ausführen

Weg A installiert zunächst für das lokale Netz (Port 3000). Eine Domain mit https wählen Sie bei Weg B gleich bei der Installation.

heinzelhaus liegt in einem privaten Repository des Herstellers unter https://git.it-flores.de/l.flores/heinzelhaus. Für den Abruf brauchen Sie ein Lesetoken. Dasselbe Token braucht später der Updater, damit das Ein-Klick-Update neue Stände holen kann: Es bleibt deshalb in der Git-Adresse (origin) im Projektordner gespeichert, in der Datei .git/config, die nur root lesen darf.

Damit heinzelhaus in einem eigenen, leichtgewichtigen Container (LXC) läuft, getrennt von allem anderen auf dem Host.

Sie brauchen: root auf dem Proxmox-Host (nicht im Container) und das Lesetoken.

  1. Geben Sie das Token auf dem Proxmox-Host an:

    Terminal-Fenster
    export HH_TOKEN=<Lesetoken>

    Ohne die Variable fragt das Skript später nach dem „Forgejo-Lesetoken“.

  2. Laden Sie das Skript herunter. Der Abruf in zwei Schritten sorgt dafür, dass ein fehlgeschlagener Download sichtbar scheitert, bevor etwas angelegt wird:

    Terminal-Fenster
    curl -fsSL -H "Authorization: token $HH_TOKEN" \
    "https://git.it-flores.de/api/v1/repos/l.flores/heinzelhaus/raw/scripts/proxmox-install.sh?ref=main" \
    -o proxmox-install.sh
  3. Führen Sie es aus:

    Terminal-Fenster
    bash proxmox-install.sh
  4. Warten Sie einige Minuten. Das Skript meldet jeden Schritt, zum Beispiel „Container 105 anlegen“ und „Im Container installieren (das dauert einige Minuten)“.

  5. Am Ende nennt es die Adresse, den Hostnamen und das Root-Passwort des Containers, zum Beispiel http://192.168.1.20:3000. Notieren Sie das Root-Passwort. Es ist nur nötig, wenn Sie sich später im Container anmelden.

  6. Öffnen Sie die Adresse im Browser und fahren Sie mit der Ersten Einrichtung fort.

  • Es prüft, ob es auf einem Proxmox-Host läuft (pct, pveam, pvesh, pvesm).
  • Es wählt den Speicher: bevorzugt local-lvm, sonst local-zfs, sonst den ersten aktiven Speicher mit Inhalt „rootdir“. Es nimmt die nächste freie Container-ID.
  • Es lädt bei Bedarf die neueste Debian-12-Vorlage.
  • Es legt einen unprivilegierten Container an, der beim Start des Hosts mitstartet, und erlaubt darin Docker (nesting=1,keyctl=1).
  • Es überträgt das Token als Datei in den Container, nicht über die Befehlszeile, klont das Repository nach /opt/heinzelhaus und ruft dort install.sh im Modus für das lokale Netz mit der IP-Adresse des Containers auf.

Setzen Sie die Variablen vor dem Aufruf, zum Beispiel HH_CTID=120 bash proxmox-install.sh. Die Vorgaben stehen in der Klammer.

Variable Bedeutung (Vorgabe)
HH_TOKEN Lesetoken, Pflicht
HH_CTID Container-ID (die nächste freie)
HH_HOSTNAME Hostname des Containers (heinzelhaus)
HH_STORAGE Speicher für das Wurzeldateisystem (wird ermittelt)
HH_TPL_STORAGE Speicher für die Vorlage (local)
HH_BRIDGE Netzbrücke (vmbr0)
HH_NET dhcp oder eine feste Adresse wie 10.0.0.5/24,gw=10.0.0.1 (dhcp)
HH_DISK_GB Platte in GB (20)
HH_CORES Prozessorkerne (2)
HH_MEM_MB Arbeitsspeicher in MB (4096)
HH_SWAP_MB Auslagerungsspeicher in MB (2048)
HH_BRANCH Git-Zweig (main)
HH_REPO_URL Repository-Adresse ohne Zugangsdaten
HH_ROOT_PW Root-Passwort im Container (zufällig, wird am Ende genannt)
HH_APPARMOR_UNCONFINED Schutzprofil des Containers lockern, siehe den Hinweis darunter (1 = ja)

Alle Variablen gelten auch unter ihrem alten Namen, etwa CASA_TOKEN, solange die HH_-Fassung fehlt.

Damit heinzelhaus auf einem vorhandenen Server oder einer virtuellen Maschine läuft.

Sie brauchen: einen Server mit Debian oder Ubuntu, root-Zugang, git und openssl (siehe Systemvoraussetzungen) und das Lesetoken.

  1. Holen Sie den Programmstand in den Projektordner. Die Zugangsdaten gehören in die Adresse, weil der Updater sie später aus der Datei .git/config liest:

    Terminal-Fenster
    git clone https://<Benutzer>:<Lesetoken>@git.it-flores.de/l.flores/heinzelhaus.git /opt/heinzelhaus
    chmod 600 /opt/heinzelhaus/.git/config
    cd /opt/heinzelhaus

    Der Projektordner darf auch woanders liegen. Das Installationsskript trägt den Pfad als REPO_PFAD in die .env ein. /opt/heinzelhaus ist die Vorgabe.

  2. Starten Sie die Installation:

    Terminal-Fenster
    sudo bash install.sh
  3. Das Skript installiert Docker, falls es fehlt („Docker wird installiert…“).

  4. Gibt es noch keine .env, fragt das Skript „Wie soll heinzelhaus erreichbar sein?“. Wählen Sie eine Antwort, siehe „Wie heinzelhaus erreichbar ist“:

    • „1) Im lokalen Netz per IP-Adresse“ (Vorgabe, die erkannte Adresse steht dabei)
    • „2) Hinter einem Reverse-Proxy mit Domain (https)“. Das Skript fragt dann nach der „Domain (ohne https://)“, zum Beispiel verwaltung.example.de.
    • „3) Nur auf diesem Host (localhost)“
  5. Das Skript schreibt die .env mit zufälligen Kennwörtern und meldet „.env geschrieben — erreichbar unter …“. Dann legt es die Datei docker-compose.override.yml aus der Vorlage an.

  6. Es baut und startet alle Container: „Container werden gebaut und gestartet (das dauert beim ersten Mal einige Minuten)…“

  7. Am Ende steht „Fertig! heinzelhaus läuft und ist erreichbar unter …“. Öffnen Sie die Adresse im Browser und fahren Sie mit der Ersten Einrichtung fort.

Läuft das Skript ohne Tastatur, etwa aus einem Auftrag, wählt es das lokale Netz. Steuern lässt es sich mit Umgebungsvariablen:

Variable Bedeutung
HH_ZUGANG lan (lokales Netz), proxy (Domain mit https) oder local (nur auf dem Server selbst)
HH_IP IP-Adresse des Servers bei lan
HH_DOMAIN Domain bei proxy
HH_PROJEKT Name der Installation, Vorgabe heinzelhaus. Eine zweite Installation auf demselben Server braucht einen eigenen Namen.

Auch diese Variablen gelten unter ihrem alten Namen weiter (CASA_ZUGANG, CASA_IP, CASA_DOMAIN).

Das Skript ist wiederholbar. Eine vorhandene .env und eine vorhandene docker-compose.override.yml überschreibt es nie. Es baut und startet die Container nur neu. Fehlen in einer vorhandenen .env die Kennwörter der Import-Server, ergänzt es sie.

Die Wahl bei der Installation bestimmt die Adresse, unter der Ihre Mitarbeitenden heinzelhaus im Browser öffnen.

Die Adresse lautet http://<IP-Adresse des Servers>:3000. Das Skript trägt BETTER_AUTH_URL=http://<IP>:3000 und APP_BIND=0.0.0.0 in die .env ein. APP_BIND entscheidet, wer den Port erreicht: Mit 0.0.0.0 auch die Rechner im Netz, mit 127.0.0.1 nur der Server selbst.

  • Geben Sie dem Server eine feste Adresse (zum Beispiel über eine Reservierung im Router). Die Adresse steht in BETTER_AUTH_URL. Aus Sicherheitsgründen vergleicht heinzelhaus die Herkunft jeder Anfrage mit dieser Adresse, als Schutz vor gefälschten Anfragen. Wer heinzelhaus unter einer anderen Adresse aufruft, kann sich deshalb unter Umständen nicht anmelden. Ändert sich die IP-Adresse, tragen Sie die neue in der .env ein und übernehmen Sie die Änderung (siehe „Docker Compose von Hand aufrufen“).
  • Über http gehen Anmeldung und Sitzung im Klartext durchs Netz. Administratoren sehen deshalb unter „Sicherheit“ den Hinweis „Verbindung ist unverschlüsselt“. Abhilfe schafft https vor der Anwendung.
  • Passkeys setzen eine Domain mit https voraus. Im lokalen Netz bleibt in der Regel die Authenticator-App für die starke Anmeldung, siehe Anmeldesicherheit und Zwei-Faktor-Pflicht.

Die Domain ermöglicht https und Passkeys. Wählen Sie bei der Installation „2) Hinter einem Reverse-Proxy mit Domain (https)“ und geben Sie die Domain ein.

Vorher muss der DNS-Eintrag (A-Record) der Domain auf den Server zeigen, und die Ports 80 und 443 müssen erreichbar sein.

Das Skript trägt dann BETTER_AUTH_URL=https://<Domain>, DOMAIN=<Domain>, PASSKEY_RP_ID=<Domain> und APP_BIND=127.0.0.1 ein. Es startet zusätzlich den Dienst Caddy:

  • Caddy holt das Zertifikat beim ersten Aufruf automatisch bei Let’s Encrypt und erneuert es.
  • Die Anwendung ist nur noch über Caddy erreichbar, nicht mehr direkt über Port 3000.
  • Caddy setzt Sicherheits-Kopfzeilen (unter anderem HSTS) und erlaubt Uploads bis 5 GB, denn Karthago-Sicherungen sind groß.
  • Caddy führt ein Zugriffsprotokoll zugriff.log im Speicherbereich caddy-data. Eine Datei wird bei 20 MiB abgeschlossen, fünf bleiben erhalten.
  • Sind die Ports 80 und 443 schon belegt, ändern Sie CADDY_HTTP_PORT und CADDY_HTTPS_PORT in der .env. Let’s Encrypt nutzt aber nur 80 und 443. Davor muss dann etwas weiterleiten.

Die Adresse lautet http://localhost:3000, und APP_BIND steht auf 127.0.0.1. Das eignet sich für Tests oder für einen Zugriff über einen SSH-Tunnel. Soll die Anwendung unter einer weiteren Adresse aufrufbar sein, tragen Sie diese kommagetrennt unter BETTER_AUTH_TRUSTED_ORIGINS ein, zum Beispiel http://localhost:3000 für einen Tunnel während der Einrichtung.

heinzelhaus besteht aus mehreren Containern. docker compose ps -a im Projektordner zeigt sie alle.

Dienst Aufgabe
db Die Datenbank (PostgreSQL 17)
init-daten Läuft einmalig und legt im Datenverzeichnis die Ordner an und setzt die Rechte
migrate Läuft bei jedem Start einmal und spielt Anpassungen der Datenbankstruktur ein
app Die Anwendung, im Container auf Port 3000
worker Der Hintergrunddienst: prüft jede Minute Fristen-Erinnerungen, geplante Sicherungen und Zahlungsrückstände, beendet unterbrochene Importe und Serienbriefe und prüft einmal täglich auf eine neue Version
pdf Der PDF-Dienst (WeasyPrint) für Abrechnungen, Briefe und Kontenblätter
updater Führt das Ein-Klick-Update aus und startet bei Bedarf die Import-Datenbankserver. Nur er hat Zugriff auf Docker.
caddy Nur mit Domain: stellt https bereit
mssql, firebird Nur während einer Datenübernahme: die Import-Datenbankserver für Karthago und PowerHaus

Die Einmal-Dienste init-daten und migrate stehen nach getaner Arbeit als beendet (Exited) in der Liste. Das ist richtig.

Die Daten liegen in Docker-Volumes. Ihre Namen beginnen mit dem Projektnamen aus HH_PROJEKT, also heinzelhaus_.

Volume Inhalt
heinzelhaus_db-data Die Datenbank
heinzelhaus_app-data Das Datenverzeichnis /data: Dokumente, hochgeladene Dateien, Logos, Sicherungen und der Update-Status
heinzelhaus_mssql-data, heinzelhaus_firebird-data Nur für die Datenübernahme
heinzelhaus_caddy-data, heinzelhaus_caddy-config Nur mit Domain: Zertifikate und Zugriffsprotokoll

Die Anwendung läuft im Container als Benutzer ohne Sonderrechte (Nummer 100, Gruppe 101).

Ihre eigenen Einstellungen gehören in zwei Dateien, die Updates nie anfassen:

  • .env: Zugangsdaten, Adresse, Ports, Domain, Zeitzone. Die Datei enthält Kennwörter und den Schlüssel BETTER_AUTH_SECRET. Sie ist nur für root lesbar. Die Sicherungen aus heinzelhaus enthalten sie nicht. Bewahren Sie deshalb eine Kopie getrennt vom Server auf, siehe Datensicherung und Wiederherstellung.
  • docker-compose.override.yml: alles Übrige, etwa Speichergrenzen und Ablageorte. Das Installationsskript legt sie aus der Vorlage docker-compose.override.yml.example an.

Die Programmdateien docker-compose.yml, docker-compose.prod.yml, Dockerfile und Caddyfile verwaltet das Update. Änderungen daran gehen beim nächsten Update verloren. Der Updater legt sie vorher als Patch unter /data/update ab.

Fehlt ein Pflichteintrag, startet Docker Compose gar nicht und nennt ihn, zum Beispiel mit „POSTGRES_PASSWORD fehlt in .env“.

Eintrag Bedeutung
HH_PROJEKT Pflicht. Name des Docker-Projekts, bestimmt Container- und Volume-Namen. Das Installationsskript trägt heinzelhaus ein.
POSTGRES_PASSWORD Pflicht. Kennwort der Datenbank, vom Skript zufällig erzeugt.
BETTER_AUTH_SECRET Pflicht. Geheimer Schlüssel für die Anmeldung, vom Skript zufällig erzeugt. Ändern Sie ihn nicht, sonst melden sich alle neu an.
MSSQL_SA_PASSWORD, FIREBIRD_PASSWORD Pflicht. Kennwörter der Import-Datenbankserver, vom Skript zufällig erzeugt.
BETTER_AUTH_URL Adresse der Installation, zum Beispiel https://verwaltung.example.de oder http://192.168.1.20:3000
PASSKEY_RP_ID Domain für Passkeys, ohne https:// und ohne Port. Sie muss zur aufgerufenen Adresse passen. Bei der Installation mit Domain setzt das Skript sie. Sonst gilt localhost.
BETTER_AUTH_TRUSTED_ORIGINS Weitere erlaubte Adressen, kommagetrennt
APP_BIND, APP_PORT Wer den Port erreicht (127.0.0.1 nur der Server, 0.0.0.0 das ganze Netz) und welcher Port (Vorgabe 3000)
DOMAIN Domain bei Betrieb mit Caddy. Ist sie gesetzt, bindet der Updater docker-compose.prod.yml ein.
CADDY_HTTP_PORT, CADDY_HTTPS_PORT Ports von Caddy (80 und 443)
HH_2FA_PFLICHT aus hebt die Pflicht zur starken Anmeldung auf, siehe Anmeldesicherheit und Zwei-Faktor-Pflicht
TZ Zeitzone, Vorgabe Europe/Berlin. Ohne sie wären Fristen und Zeitstempel um Stunden versetzt.
REPO_PFAD Pfad des Projektordners auf dem Server, Vorgabe /opt/heinzelhaus. Er muss stimmen, sonst scheitern Updates mit „not a directory“.

Ändern Sie etwas in der .env, übernehmen Sie es mit docker compose up -d im Projektordner. Das erneuert nur die Container, deren Einstellungen sich geändert haben. Wie Sie es aufrufen, hängt vom Zugang ab:

Terminal-Fenster
cd /opt/heinzelhaus
# Im lokalen Netz (kein DOMAIN in der .env)
docker compose up -d
# Mit Domain (DOMAIN in der .env): alle drei Dateien nennen
docker compose -f docker-compose.yml -f docker-compose.prod.yml -f docker-compose.override.yml up -d

Beim Betrieb mit Domain brauchen Sie die Dateiliste. Ohne sie lässt Compose den Dienst Caddy aus. Dieselbe Dateiwahl treffen das Installationsskript und der Updater. Die Override-Datei nennen Sie ausdrücklich, weil Compose sie bei einer ausdrücklichen Dateiliste nicht von selbst lädt.

Bequemer ist eine Zeile in der .env, dann genügt ein einfaches docker compose up -d:

Terminal-Fenster
COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml:docker-compose.override.yml

Die Vorlage docker-compose.override.yml.example zeigt Beispiele. Zum Aktivieren entfernen Sie die Kommentarzeichen bei services: und bei dem gewünschten Block. Steht services: allein und leer da, bricht jeder Compose-Aufruf ab.

  • Portbindung: einfacher über APP_BIND und APP_PORT in der .env.
  • Speichergrenzen: mem_limit für app, db und worker. Auf kleinen Servern verhindert das, dass der Kernel bei Speichermangel wahllos einen Dienst beendet, auch mitten im Update.
  • Abweichende Ablageorte: Die Daten statt in Volumes auf einer eigenen Platte oder einem NAS halten. Der Wechsel verschiebt keine vorhandenen Daten. Sichern Sie zuerst (Einstellungen → Reiter „Backup“), stellen Sie dann um und spielen Sie die Daten zurück.
  • Protokollgrenzen: Ohne Deckel wächst das Docker-Protokoll unbegrenzt und füllt irgendwann die Platte.
  • Eigene Caddy-Konfiguration oder eigene zusätzliche Dienste.

Ein zusätzliches Laufwerk für Sicherungen binden Sie in beide Dienste app und worker ein, denn der Hintergrunddienst schreibt die geplanten Sicherungen. Das Beispiel hängt /mnt/nas/heinzelhaus-backups als /backups ein:

services:
app:
volumes:
- /mnt/nas/heinzelhaus-backups:/backups
worker:
volumes:
- /mnt/nas/heinzelhaus-backups:/backups

Danach wählen Sie /backups in den Einstellungen als Speicherort, siehe Datensicherung und Wiederherstellung.

Öffnen Sie die Adresse im Browser. Solange noch kein Benutzer existiert, führt die Anmeldeseite von selbst zur Ersteinrichtung. Dort legen Sie das erste Administratorkonto an: Erste Einrichtung.

Meldung Bedeutung und Abhilfe
„Bitte als root ausführen (oder mit sudo).“ Das Installationsskript braucht root-Rechte.
„Docker-Dienst nicht bereit — bitte prüfen (systemctl status docker).“ Docker startet nicht. Prüfen Sie den Dienst, in einem Proxmox-Container auch die Optionen „nesting“ und „keyctl“.
„HH_PROJEKT fehlt in .env - vor 1.0 eingerichtete Installation? …“ Die Installation stammt aus der Zeit vor Version 1.0. Siehe Umzug von CasaTastic auf heinzelhaus.
„POSTGRES_PASSWORD fehlt in .env“, „BETTER_AUTH_SECRET fehlt in .env“ Ein Pflichteintrag fehlt in der .env. Tragen Sie ihn ein.
„DOMAIN fehlt in .env“ docker-compose.prod.yml ist eingebunden, aber DOMAIN ist nicht gesetzt. Setzen Sie die Domain, oder lassen Sie die Datei weg.
„not a directory“ beim Start oder bei einem Update REPO_PFAD in der .env stimmt nicht mit dem Projektordner überein.
„Bitte als root auf dem Proxmox-Host ausführen.“ Das Proxmox-Skript gehört auf den Host, nicht in den Container, und braucht root.
„Kein Token (HH_TOKEN) angegeben — …“ Setzen Sie das Lesetoken, siehe Weg A.
„Container … existiert bereits. Andere HH_CTID wählen oder ihn zuerst entfernen …“ Die Container-ID ist belegt. Wählen Sie eine andere mit HH_CTID.
„Keinen Speicher mit Inhalt ‘rootdir’ gefunden. …“ Geben Sie den Speicher mit HH_STORAGE an. Das Skript nennt die vorhandenen Speicher.
„Container hat nach 60 s keine IP-Adresse. Netzbrücke (vmbr0) und DHCP prüfen.“ Prüfen Sie HH_BRIDGE und den DHCP-Dienst, oder geben Sie mit HH_NET eine feste Adresse vor.
„Installation im Container fehlgeschlagen. Hineinsehen mit: pct enter …“ Sehen Sie in den Container und lesen Sie die Ausgabe. Häufig fehlt Internetzugang, das Token ist falsch oder der Platz reicht nicht.

heinzelhaus ist ein Produkt und eine Marke der IT Systeme Flores UG (haftungsbeschränkt), Bergisch Gladbach.

© 2026 IT Systeme Flores UG