On-Premise installieren
Heinzel Pro ist ein Container plus PostgreSQL. Diese Anleitung führt von einem leeren Host bis zur ersten Anmeldung, mit jedem Befehl zum Kopieren. Wer Docker Compose kennt, braucht eine Stunde, die Hälfte davon für Mail und Proxy.
Am Ende läuft Heinzel Pro unter https://heinzel.example.com, hinter einem Reverse Proxy mit TLS, schickt Mail, und das erste Konto ist Administrator der Installation. Ersetzen Sie heinzel.example.com überall durch Ihren Namen.
Was Sie brauchen
| Voraussetzung | Prüfen mit |
|---|---|
| Ein Linux-Host, x86_64 oder arm64, mit Docker und Compose v2 | docker compose version antwortet mit „Docker Compose version v2.…“ oder, aus Debians Paketen, „2.…“. Auf Debian 13 bringt sudo apt install docker.io docker-compose beides mit. Die Anwendung selbst braucht wenig; Rechner und Speicher bestimmt PostgreSQL, und die wächst mit Sessions und Audit-Protokoll. |
| Ein DNS-Name, der auf den Host zeigt | dig +short heinzel.example.com nennt die Adresse des Hosts. |
| Port 443 (und 80 für Let’s Encrypt) aus dem Netz der Benutzer erreichbar | Für ein reines Intranet reicht das Intranet; siehe „Ohne TLS“ unten. |
| Ein Weg für Mail | Ein Mailserver, ein Konto bei Gmail oder Microsoft 365, oder ein Mail-Dienst. Ohne Mail gibt es keine Einladungen und keine Berichte; die Einrichtung steht unten. |
| Ein API-Schlüssel für ein Modell | Anthropic oder ein OpenAI-kompatibler Anbieter, oder ein Modell im eigenen Netz. Kommt erst nach der Installation ins Spiel. |
| SSH vom Host zu den Servern, die Heinzel betreuen soll | nc -zv web01.example.com 22 vom Host aus. Server ohne Weg dorthin erreicht Heinzel später über VPN. |
Das Image ghcr.io/wintermeyer/heinzel-pro ist öffentlich; ein GitHub-Konto oder eine Anmeldung an der Registry braucht es nicht. Es gibt es für amd64 und arm64.
1. Ein Verzeichnis und zwei Dateien
Alles liegt in einem Verzeichnis, das nur root liest. Darin eine docker-compose.yml und eine .env.
$ sudo install -d -m 750 /opt/heinzel-pro
$ cd /opt/heinzel-prodocker-compose.yml
Übernehmen Sie die Datei unverändert:
# Heinzel Pro on a single host. Copy .env.example to .env, fill it in, then:
#
# docker compose up -d
#
# Put a TLS-terminating reverse proxy (Caddy, Traefik, nginx) in front of
# 127.0.0.1:4000, or set FORCE_SSL=false and HEINZEL_BASE_URL to an http:// URL for an
# internal network.
services:
app:
image: ghcr.io/wintermeyer/heinzel-pro:${HEINZEL_VERSION:?Set HEINZEL_VERSION in .env to the version to run}
restart: unless-stopped
# Time to end in good order: runners finish the poll they are in and
# give their sessions back, so the next start resumes them at once.
stop_grace_period: 90s
env_file: .env
environment:
DATABASE_URL: ecto://heinzel@db/heinzel_pro
DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
POOL_SIZE: "10"
# Loopback only by default; the reverse proxy on the host is the public face.
ports:
- "${HEINZEL_PORT:-127.0.0.1:4000}:4000"
# VPN connections that a tenant's server or network dials, one UDP port
# each. They must be reachable from the internet, and free on the host:
# a port something else listens on keeps this container from starting.
# With HEINZEL_VPN_PORTS=none, remove this line.
- "${HEINZEL_VPN_PORTS:-51900-51919}:${HEINZEL_VPN_PORTS:-51900-51919}/udp"
depends_on:
db:
condition: service_healthy
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges:true
db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_USER: heinzel
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: heinzel_pro
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U heinzel -d heinzel_pro"]
interval: 10s
timeout: 5s
retries: 10
volumes:
pgdata:Drei Dinge, die die Datei absichtlich tut: Sie bindet die Anwendung an 127.0.0.1, weil Docker veröffentlichte Ports an der Firewall des Hosts vorbeiführt. Sie nennt die Version aus HEINZEL_VERSION und startet ohne die Zeile nicht, damit ein docker compose pull nie ein Upgrade aus Versehen ist. Und sie öffnet zwanzig UDP-Ports für VPN-Verbindungen, die sich bei Heinzel einwählen; wer das nicht braucht, setzt HEINZEL_VPN_PORTS=none in der .env und entfernt die UDP-Zeile.
.env
Die Einstellungen und Geheimnisse. Erzeugen Sie zuerst vier Zufallswerte:
$ openssl rand -base64 48 # SECRET_KEY_BASE
$ openssl rand -base64 32 # HEINZEL_VAULT_KEY
$ openssl rand -base64 32 # POSTGRES_PASSWORD
$ openssl rand -base64 32 # HEINZEL_OPS_TOKENDann die Datei, mit Ihren Werten:
# /opt/heinzel-pro/.env
# Die Adresse, die Benutzer öffnen
PHX_HOST=heinzel.example.com
HEINZEL_BASE_URL=https://heinzel.example.com
# Die vier Zufallswerte von oben
SECRET_KEY_BASE=…
HEINZEL_VAULT_KEY=…
HEINZEL_VAULT_KEY_ID=1
POSTGRES_PASSWORD=…
HEINZEL_OPS_TOKEN=…
# Die Version, die laufen soll. Beim Upgrade ändern Sie diese Zeile.
HEINZEL_VERSION=2.68.2
# Mail, siehe Schritt 2
MAIL_TRANSPORT=smtp
MAIL_FROM=heinzel@example.com
MAIL_FROM_NAME=Heinzel Pro
SMTP_HOST=mail.example.com
SMTP_PORT=587
SMTP_USERNAME=heinzel@example.com
SMTP_PASSWORD=…
SMTP_TLS=starttls
# Hinter einem Proxy mit TLS: http auf https umleiten, HSTS senden
FORCE_SSL=true
LOG_LEVEL=info
HEINZEL_PORT=127.0.0.1:4000$ sudo chmod 600 /opt/heinzel-pro/.envHEINZEL_VERSION ist die Version zur Zeit dieses Textes. Nehmen Sie die aktuelle; jede Version ist ein Tag des Images.
2. Mail
Heinzel Pro verschickt Anmeldelinks, Einladungen, Alarme und Berichte. Ohne Mail kommt niemand außer dem ersten Konto hinein. Eine Einrichtung, die nicht senden könnte (ein fehlender Schlüssel, halbe Zugangsdaten), hält den Start mit einer Zeile an, die die Variable nennt. Vier Wege, einer davon in die .env:
Ein Mailserver oder ein Konto (smtp)
# Der eigene Mailserver oder ein Relay
MAIL_TRANSPORT=smtp
SMTP_HOST=mail.example.com
SMTP_PORT=587
SMTP_USERNAME=heinzel@example.com
SMTP_PASSWORD=…
SMTP_TLS=starttls
# Google Workspace oder Gmail: ein App-Passwort, die Adresse als Benutzer und Absender
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USERNAME=heinzel@example.com
SMTP_PASSWORD=abcd efgh ijkl mnop
MAIL_FROM=heinzel@example.com
# Microsoft 365 mit SMTP AUTH für dieses Postfach
SMTP_HOST=smtp.office365.com
SMTP_PORT=587
SMTP_USERNAME=heinzel@example.com
SMTP_PASSWORD=…SMTP_TLS=starttls verschlüsselt, wenn der Server es anbietet, und besteht darauf, sobald ein Passwort gesetzt ist; always besteht immer darauf, never sendet im Klartext. Port 465 heißt TLS ab dem ersten Byte. Eine eigene Zertifizierungsstelle kommt als PEM-Datei in den Container (SMTP_CA_FILE), ein Zertifikat, das sich nicht prüfen lässt, nimmt SMTP_TLS_VERIFY=false an.
Ein Postfix auf dem Docker-Host selbst: extra_hosts: ["host.docker.internal:host-gateway"] unter app in der Compose-Datei, dann SMTP_HOST=host.docker.internal, SMTP_PORT=25, keine Zugangsdaten und SMTP_TLS=never. Die Mail kommt aus dem Netz, das Compose für dieses Verzeichnis anlegt, nicht von der Bridge docker0, und dessen Adressen wählt Docker bei jedem docker compose down neu. Legen Sie es deshalb am Ende der Compose-Datei fest, auf einen Bereich, den Ihr Netz nicht benutzt:
networks:
default:
ipam:
config:
- subnet: 172.30.79.0/24Postfix muss auf allen Schnittstellen lauschen (inet_interfaces = all, Debians Vorgabe), dieses Netz annehmen, und die Firewall des Hosts muss es zu Port 25 durchlassen:
$ sudo postconf -e "mynetworks = $(postconf -h mynetworks) 172.30.79.0/24"
$ sudo systemctl reload postfix
$ sudo ufw allow from 172.30.79.0/24 to any port 25 proto tcpOhne die Firewall-Regel endet die Testmail mit {:network_failure, ~c"host.docker.internal", {:error, :timeout}}.
Microsoft 365 ohne SMTP (msgraph)
MAIL_TRANSPORT=msgraph
MSGRAPH_TENANT_ID=…
MSGRAPH_CLIENT_ID=…
MSGRAPH_CLIENT_SECRET=…
MAIL_FROM=heinzel@example.comEine App-Registrierung in Entra ID mit der Anwendungsberechtigung Mail.Send und der Zustimmung eines Administrators. MAIL_FROM ist das Postfach, als das sie sendet.
Ein Mail-Dienst über HTTPS
# Postmark, Resend, SendGrid, Brevo, Mailersend, Mailpace, Mailtrap, SMTP2GO, SparkPost, ZeptoMail
MAIL_TRANSPORT=postmark
MAIL_API_KEY=…
# Mailjet: Schlüssel und Secret; Scaleway: MAIL_PROJECT_ID und MAIL_API_SECRET
# Amazon SES: MAIL_REGION, MAIL_API_KEY (Access Key ID), MAIL_API_SECRET
# Postal: MAIL_API_KEY und MAIL_API_URL (der eigene Server)Für ein Netz, das kein SMTP hinauslässt. Mailgun und jeder Dienst, der hier fehlt, geht über smtp mit den SMTP-Zugangsdaten, die der Dienst ausgibt.
Das Mail-Kommando der Maschine (sendmail)
Nur für ein Release, das ohne Container direkt auf einem Host läuft. Das Container-Image bringt kein Mail-Kommando mit; dort geht die Mail per smtp an den Server des Hosts.
MAIL_FROM ist der Absender für jeden Weg. Die meisten Anbieter nehmen nur eine Adresse oder Domain an, die bei ihnen bestätigt ist.
3. Starten und prüfen
$ cd /opt/heinzel-pro
$ sudo docker compose up -d
$ sudo docker compose logs -f app # bis die Anwendung läuft, dann Strg-CDer erste Start holt das Image, legt die Datenbank an und führt die Migrationen aus, bevor er Anfragen beantwortet. Dann:
$ curl -s http://127.0.0.1:4000/health
{"status":"ok","version":"2.68.2","database":"ok","rules_version":"3.3.1","pending_migrations":0}/health antwortet nur dann mit 200, wenn die Datenbank erreichbar ist und keine Migration aussteht. Eine andere Antwort heißt warten oder in das Log sehen; was dort stehen kann, steht unter Wenn etwas hakt.
4. Der Reverse Proxy
Heinzel Pro spricht HTTP auf 127.0.0.1:4000. Davor gehört ein Proxy, der TLS beendet. Er muss drei Dinge tun: Host und X-Forwarded-Proto durchreichen und WebSocket-Upgrades erlauben, weil jede Seite eine Verbindung offen hält. Zwei fertige Konfigurationen.
Caddy
Caddy besorgt das Zertifikat selbst und reicht WebSockets und beide Header von Haus aus durch. Die ganze Datei:
# /etc/caddy/Caddyfile
heinzel.example.com {
# Einen Neustart ankündigen darf nur der Host selbst, nie jemand von außen.
respond /ops/* 404
reverse_proxy 127.0.0.1:4000
}$ sudo systemctl reload caddynginx
# /etc/nginx/sites-available/heinzel-pro
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name heinzel.example.com;
# Ihr Zertifikat, von Let’s Encrypt oder Ihrer eigenen Zertifizierungsstelle.
ssl_certificate /etc/letsencrypt/live/heinzel.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/heinzel.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
# Die Seiten halten einen WebSocket offen.
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
}
# Einen Neustart ankündigen darf nur der Host selbst, nie jemand von außen.
location /ops/ {
return 404;
}
}
server {
listen 80;
listen [::]:80;
server_name heinzel.example.com;
return 301 https://$host$request_uri;
}$ sudo ln -s /etc/nginx/sites-available/heinzel-pro /etc/nginx/sites-enabled/
$ sudo nginx -t && sudo systemctl reload nginxDas Zertifikat muss liegen, bevor nginx die Datei lädt. Läuft nginx schon und zeigt der Name auf den Host, holt certbot es vorher und erneuert es später selbst:
$ sudo certbot certonly --nginx -d heinzel.example.comAb nginx 1.25 warnt nginx -t, listen … http2 sei veraltet; die Zeile funktioniert trotzdem, und ältere Versionen kennen den Ersatz http2 on; nicht. Wer gar nichts einrichten will, nimmt Caddy.
Ohne TLS, im abgeschotteten Netz
Wo kein Proxy und kein Zertifikat sein soll, lauscht die Anwendung direkt: HEINZEL_PORT=0.0.0.0:4000, FORCE_SSL=false und HEINZEL_BASE_URL=http://heinzel.intranet:4000 in der .env. Passkeys funktionieren dann nicht; Browser verlangen dafür HTTPS.
Hinter zwei Proxys
Steht vor dem Proxy noch ein Load-Balancer, setzen Sie TRUSTED_PROXIES=2, sonst zählt das Anmelde-Limit jeden Besucher als den Load-Balancer. Ein zweiter Name für dieselbe Installation kommt in EXTRA_ORIGINS, durch Komma getrennt.
5. Die Firewall
Offen sein müssen 443 und 80 für die Benutzer und, wenn VPN-Verbindungen sich einwählen sollen, die UDP-Ports. Port 4000 bleibt zu; die Compose-Datei bindet ihn an die Loopback-Adresse.
$ sudo ufw allow 22/tcp
$ sudo ufw allow 80,443/tcp
$ sudo ufw allow 51900:51919/udp # entfällt mit HEINZEL_VPN_PORTS=none
$ sudo ufw enableDie UDP-Ports müssen auf dem Host frei sein: Lauscht dort schon etwas auf einem von ihnen, startet der Container nicht. ss -lun zeigt, was belegt ist; der Bereich meidet 51820, den üblichen Port eines WireGuard auf dem Host. Zeigt die Webadresse nicht auf diese Maschine (CDN, getrennter Proxy), nennt HEINZEL_VPN_HOST den Namen, den die Gegenseite anwählt.
6. Die erste Anmeldung
https://heinzel.example.com/auth/registeröffnen. E-Mail und Passwort wählen. Das erste Konto wird Administrator der Installation und ist sofort angemeldet; danach ist die Registrierung geschlossen, alle weiteren werden eingeladen.- Nutzungsbedingungen annehmen. Einmal für sich und einmal für den Kunden (Unternehmen, Organisation oder Privatperson). Bis dahin warten die Seiten, und die API antwortet 403.
Installation, Mailversand: eine Testmail schicken. Kommt sie an, kommen auch Einladungen an. Kommt sie nicht, steht der Grund im Log:
sudo docker compose logs app | grep -i mail- Installation, Protokoll öffnen. Der Kasten „Betrieb“ sagt in einer Zeile, ob alles läuft: Version, Regelwerk, Lizenz, Mailversand, Datenbank migriert, Not-Aus, Hintergrundjobs.

.env eingerichtet, gefolgt von einem Neustart; hier prüfen Sie sie.
.env steht; ob Mail ankommt, zeigt erst die Testmail.Von der Shell aus geht die Testmail auch:
$ sudo docker compose run --rm app bin/heinzel_pro eval 'HeinzelPro.Release.test_mail("sie@example.com")'
handed over for sie@example.com„Übergeben“ heißt: Der Mailserver hat die Mail angenommen. Ob sie ankommt, entscheidet der Empfänger; ein Absender ohne SPF und DKIM landet bei großen Anbietern oft im Spam oder nirgends.
7. Die Lizenz
Ohne Schlüssel läuft die Installation 14 Tage als Testphase mit drei Plätzen. Den Schlüssel, den Sie von uns bekommen, fügen Sie unter Installation, Einstellungen, Lizenz ein. Er wird offline geprüft und nirgendwohin gesendet. Ein Platz ist jeder Benutzer, der handeln kann; Rechte zum Ansehen sind frei. Nach Ablauf eines Schlüssels gibt es 14 Tage Kulanz mit Banner, danach starten keine neuen Sessions, und alles Aufgezeichnete bleibt lesbar.

8. Und dann
Das erste Konto steckt schon in einem Mandanten namens „Default“. Unter Einstellungen, Allgemein bekommt er seinen Namen und seine Zeitzone; ein neuer Mandant steht auf UTC, und danach richten sich Zeitpläne und jede Uhrzeit auf den Seiten. Dann Modellanbieter eintragen, den ersten Server anlegen, die erste Session: Erste Schritte, ab Abschnitt 3. Die Pflege der Installation, Sicherung voran, steht unter Betrieb, und dort auch, wie Sie Heinzel Pro wieder entfernen.
Checkliste
/opt/heinzel-pro/.envhat Modus 600, und eine Kopie liegt bei der Datenbanksicherung.curl -s http://127.0.0.1:4000/healthnennt die Version und"pending_migrations":0.https://heinzel.example.comöffnet die Anmeldeseite, und das Schloss im Browser ist zu.- Eine Seite bleibt verbunden: Nach einer Minute auf der Übersicht steht kein Banner über einer verlorenen Verbindung.
curl -s http://heinzel.example.comantwortet mit einer Umleitung auf https.https://heinzel.example.com/ops/drainantwortet von außen mit 404.- Die Testmail ist angekommen.
- Port 4000 ist von außen zu:
nc -zv heinzel.example.com 4000von einer anderen Maschine scheitert. ss -lunzeigt die UDP-Ports 51900 bis 51919 bei Docker, und die Firewall lässt sie durch; oderHEINZEL_VPN_PORTS=nonesteht in der.env.- Die erste Sicherung ist gelaufen (siehe Betrieb, Sicherung).
Varianten
Mit Ihrer eigenen PostgreSQL
Wo das Rechenzentrum schon eine PostgreSQL betreibt und sichert (ab Version 15), nehmen Sie diese und lassen den Dienst db weg. Eine Rolle und eine Datenbank, die ihr gehört, mehr braucht es nicht, keinen Superuser:
CREATE ROLE heinzel_pro LOGIN PASSWORD '…';
CREATE DATABASE heinzel_pro OWNER heinzel_pro;In der .env entfällt POSTGRES_PASSWORD; stattdessen DATABASE_URL=ecto://heinzel_pro@db.example.com/heinzel_pro, DATABASE_PASSWORD und für TLS zur Datenbank DATABASE_SSL=true. In der Compose-Datei entfernen Sie den Dienst db, das depends_on und die drei Zeilen unter environment. POOL_SIZE (Vorgabe 10) sind die Verbindungen eines Containers.
Kubernetes
Ein Deployment mit dem Image, die .env als Secret, PostgreSQL als Dienst des Clusters. GET /health ist die Readiness-Probe. Als preStop-Hook rufen Sie /ops/drain auf (siehe Upgrade, Neustart ankündigen) und geben dem Pod eine terminationGracePeriodSeconds über der angekündigten Zeit. Die VPN-Ports brauchen einen Service vom Typ LoadBalancer oder hostPort.
Ohne Weg ins Internet
Eine Installation ohne Internet läuft mit einem Modell im eigenen Netz (Ollama, vLLM, LM Studio). Läuft Ollama auf dem Docker-Host selbst, heißt die Basis-URL http://host.docker.internal:11434/v1 (mit der extra_hosts-Zeile aus Schritt 2), Ollama muss auf allen Schnittstellen lauschen (OLLAMA_HOST=0.0.0.0), und die Firewall lässt das Compose-Netz zu Port 11434 durch, wie oben für Port 25. Das Regelwerk kommt als Datei: das .tar.gz eines Tags des öffentlichen Heinzel-Repositorys, unter Installation, Einstellungen, Regelwerk hochgeladen. Mail geht an den eigenen Server. Sonst ändert sich nichts; Heinzel Pro ruft von sich aus nichts auf, was Sie nicht eingetragen haben (die Liste steht unter Betrieb).
Alle Umgebungsvariablen
| Variable | Zweck |
|---|---|
PHX_HOST, HEINZEL_BASE_URL | Die öffentliche Adresse; PHX_SCHEME und PHX_PUBLIC_PORT, wo sie von https und 443 abweicht. |
SECRET_KEY_BASE | Signiert Cookies und Tokens. |
HEINZEL_VAULT_KEY, HEINZEL_VAULT_KEY_ID | Verschlüsselung gespeicherter Geheimnisse; Rotation siehe Betrieb. |
HEINZEL_VERSION | Die Version, die läuft. Pflicht. |
DATABASE_URL, DATABASE_PASSWORD, DATABASE_SSL | ecto://user@host/db plus Passwort; true für TLS zur Datenbank. Die Compose-Datei setzt die ersten beiden für die mitgebrachte PostgreSQL. |
POOL_SIZE | Datenbankverbindungen, Vorgabe 10. |
FORCE_SSL | Umleitung auf https hinter einem Proxy, der X-Forwarded-Proto setzt. Anfragen auf localhost bleiben unverschlüsselt, für den Health-Check. |
TRUSTED_PROXIES | Wie viele eigene Proxys davor stehen (Vorgabe 1 mit FORCE_SSL, sonst 0). Anmelde-Limit und Audit-Protokoll nehmen die Adresse des Clients aus dem Eintrag von X-Forwarded-For, der so viele Stellen vom Ende steht. |
EXTRA_ORIGINS | Weitere erlaubte WebSocket-Origins, durch Komma getrennt. |
HEINZEL_PORT | Wo die Anwendung auf dem Host lauscht, Vorgabe 127.0.0.1:4000. |
MAIL_TRANSPORT, MAIL_FROM, MAIL_FROM_NAME, SMTP_*, MAIL_API_*, MSGRAPH_*, SENDMAIL_* | Wie Mail das Haus verlässt, siehe Schritt 2. SMTP_HELO ist der Name, mit dem sich die Installation meldet, Vorgabe PHX_HOST. |
HEINZEL_VPN_PORTS, HEINZEL_VPN_HOST | UDP-Ports für VPN-Verbindungen (Vorgabe 51900-51919, none für keine) und der Name, den die Gegenseite anwählt. |
HEINZEL_OPS_TOKEN | Was der Host vorzeigt, um einen Neustart anzukündigen. Ohne ihn gibt es die Adresse nicht. |
HEINZEL_RULES_DIR | Ein eingehängtes Verzeichnis als Regelwerk, über allem, was in der Datenbank liegt; die Regelwerk-Seite bietet dann kein Update an. |
HEINZEL_LICENSE_PUBLIC_KEY | Nur, wenn Sie eigene Lizenzen ausstellen. |
HEINZEL_HOSTED, HEINZEL_REFUSED_NETWORKS | Für eine Installation, die fremde Mandanten hostet: lehnt Adressen ab, die zur Installation selbst zurückführen, und die genannten Netze. Im eigenen Haus nicht setzen. |
HEINZEL_SKIP_MIGRATIONS | 1, um ohne Migrationen zu starten. |
LOG_LEVEL | debug, info, warning, error. |
HEINZEL_NODE_ID, HEINZEL_NODE_ADDRESS, HEINZEL_CLUSTER_NODES, HEINZEL_CLUSTER_COOKIE, HEINZEL_DIST_PORT, HEINZEL_LISTEN | Nur für zwei Slots, siehe Upgrade. |
Wenn etwas hakt
| Was Sie sehen | Woran es liegt | Was zu tun ist |
|---|---|---|
docker compose up sagt „Set HEINZEL_VERSION in .env to the version to run“ | Die Zeile fehlt. Compose nimmt absichtlich kein latest. | HEINZEL_VERSION=2.68.2 in die .env, noch einmal starten. |
| Der Container startet immer wieder neu; das Log nennt einen UDP-Port | Auf dem Host lauscht schon etwas auf einem Port zwischen 51900 und 51919. | ss -lun zeigt, was. Anderen Bereich wählen (HEINZEL_VPN_PORTS=51920-51939) oder none und die UDP-Zeile entfernen. |
Der Start bricht mit einer Zeile ab, die SMTP_ oder MAIL_ nennt | Die Mail-Einrichtung ist halb: ein Benutzer ohne Passwort, ein Dienst ohne Schlüssel. | Die genannte Variable füllen oder den Weg ganz entfernen. |
/health antwortet nicht mit 200 oder zeigt pending_migrations über 0 | Die Datenbank ist noch nicht da, oder die Migrationen laufen noch. | Eine Minute warten. Danach docker compose logs app und docker compose ps: Ist db „healthy“? |
| Die Seite lädt, aber nach Sekunden steht ein Banner über die verlorene Verbindung, und Formulare reagieren nicht | Der Proxy reicht WebSockets nicht durch, oder der Name im Browser ist nicht der in HEINZEL_BASE_URL. | Upgrade- und Connection-Header wie oben setzen. Zweiten Namen in EXTRA_ORIGINS eintragen. |
| Der Browser meldet zu viele Umleitungen | FORCE_SSL=true, aber der Proxy schickt kein X-Forwarded-Proto. | Den Header setzen; ohne Proxy FORCE_SSL=false. |
| Die Anmeldung zählt jeden Versuch gegen alle Benutzer und sperrt früh | Hinter zwei Proxys sieht die Anwendung nur die Adresse des ersten. | TRUSTED_PROXIES=2 |
/auth/register sagt, die Registrierung sei geschlossen | Es gibt schon ein Konto. | Anmelden. Kennt niemand das Passwort: docker compose exec app bin/login-link admin@example.com erzeugt einen Anmeldelink, der 15 Minuten gilt. |
| Die Testmail kommt nicht an | Der Anbieter lehnt den Absender ab, oder der Server nimmt die Verbindung nicht an. | docker compose logs app | grep -i mail nennt die Antwort des Servers. MAIL_FROM muss eine beim Anbieter bestätigte Adresse sein. |
| Eine VPN-Verbindung bleibt bei „wartet auf die Gegenseite“ | Die UDP-Ports sind in der Firewall des Hosts zu, oder die Webadresse zeigt auf eine andere Maschine. | Firewall öffnen; HEINZEL_VPN_HOST setzen, wenn der Name des Hosts ein anderer ist. |
Bleibt etwas hängen, schreiben Sie an support@heinzel-pro.de mit der Zeile aus dem Log. Im Enterprise-Plan begleiten wir die Erstinstallation remote.