ToolJet mit Docker installieren: Open-Source Low-Code-Plattform für interne Tools und Dashboards
ToolJet ist eine Open-Source-Low-Code-Plattform für interne Tools, Dashboards und Business-Apps mit über 80 Datenquellen. Die Anleitung zeigt die Installation von ToolJet v3.20 LTS mit Docker Compose, PostgreSQL und PostgREST auf einem Linux-Host.
Werbung Mit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

ToolJet ist eine Low-Code-Plattform (AGPL-3.0) für Admin-Panels, CRUD-Oberflächen (Anlegen, Lesen, Ändern, Löschen von Datensätzen) und Freigabe-Workflows. Sie verbindet per Drag-and-Drop über 80 Datenquellen, von PostgreSQL und MySQL über REST- und GraphQL-APIs bis zu S3, und erzeugt daraus Web-Anwendungen. Diese Anleitung zeigt, wie Sie ToolJet v3.20 LTS auf einem Linux-Host per Docker Compose aufsetzen.
Voraussetzungen
- Linux-Host oder VM mit x86_64-Architektur (kein ARM64, kein Apple Silicon ohne Rosetta-Emulation); Ubuntu 22.04 LTS oder Debian 12 empfohlen
- Docker Engine ≥ 20.10 und Docker Compose Plugin v2 (
docker compose, nicht das veraltetedocker-compose); falls noch nicht installiert: Docker und Docker Compose auf Linux installieren - Mindestens 1 vCPU und 2 GB RAM laut Hersteller; mit PostgreSQL und PostgREST auf demselben Host planen Sie 2 vCPUs und 4 GB RAM ein
- Mindestens 8 GB freier Festplattenspeicher (das ToolJet-Image allein ist rund 1,6 GB groß)
- Für Ihre Nutzer erreichbare IP-Adresse oder Domain für die
TOOLJET_HOST-Variable (inklusive Protokoll, z. B.http://192.168.1.10:3000) opensslauf dem Host installiert (auf Ubuntu/Debian standardmäßig vorhanden)- Optional: SMTP-Zugangsdaten für E-Mail-Einladungen, Domain und SSL-Zertifikat für HTTPS hinter einem Reverse Proxy
Schritt 1: Projektordner anlegen
Legen Sie einen eigenen Ordner für den ToolJet-Stack an; Konfiguration und Datenbank-Bind-Mount liegen hier:
$ mkdir -p /opt/tooljet
$ cd /opt/tooljet
$ mkdir postgres_dataDie Herstellervorlage legt postgres_data ebenfalls vor dem ersten Start an; so ist klar, wo die Datenbankdateien liegen.
ls -la /opt/tooljet/ zeigt den Unterordner postgres_data/.
$ ls -la /opt/tooljet/# Erwartete Ausgabe:
# drwxr-xr-x 3 root root 4096 Jun 11 10:00 .
# drwxr-xr-x 12 root root 4096 Jun 11 10:00 ..
# drwxr-xr-x 2 root root 4096 Jun 11 10:00 postgres_dataSchritt 2: Secrets erzeugen und .env anlegen
ToolJet benötigt drei Secrets, die Sie einmalig vor dem ersten Start erzeugen. Ändern Sie sie danach nicht mehr, sonst werden gespeicherte Datenquellen-Zugangsdaten und Sitzungen ungültig.
# SECRET_KEY_BASE (64 Byte Hex, für Session-Cookies)$ openssl rand -hex 64
# LOCKBOX_MASTER_KEY (32 Byte Hex, für Datasource-Credential-Verschlüsselung)$ openssl rand -hex 32
# PGRST_JWT_SECRET (32 Byte Hex, für PostgREST JWT)$ openssl rand -hex 32Tragen Sie die drei Ausgaben in eine neue Datei /opt/tooljet/.env ein und ersetzen Sie alle Platzhalter. Die ToolJet-Anwendungsdaten (PG_DB) und die ToolJet-Datenbank für eigene Tabellen (TOOLJET_DB) liegen wie in der Herstellervorlage in zwei getrennten Datenbanken derselben Instanz; ToolJet legt tooljet_db beim Start selbst an:
# === ToolJet Secrets – NIEMALS in Git committen! ===
SECRET_KEY_BASE=IHR_64BYTE_HEX_WERT
LOCKBOX_MASTER_KEY=IHR_32BYTE_HEX_WERT
PGRST_JWT_SECRET=IHR_ZWEITER_32BYTE_HEX_WERT
# === ToolJet Host: Adresse, unter der Nutzer ToolJet aufrufen ===
TOOLJET_HOST=http://192.168.1.10:3000
# === PostgreSQL-Zugangsdaten ===
PG_HOST=postgres
PG_DB=tooljet_production
PG_USER=tooljet
PG_PASS=sicheres_passwort_hier
PG_PORT=5432
# === ToolJet-Datenbank (gleiche Instanz, eigene Datenbank) ===
TOOLJET_DB=tooljet_db
TOOLJET_DB_HOST=postgres
TOOLJET_DB_USER=tooljet
TOOLJET_DB_PASS=sicheres_passwort_hier
TOOLJET_DB_PORT=5432
# === PostgREST Verbindungs-URI ===
PGRST_DB_URI=postgres://tooljet:sicheres_passwort_hier@postgres:5432/tooljet_db
# === Optionale Härtung ===
DISABLE_TOOLJET_TELEMETRY=true
DISABLE_SIGNUPS=trueSchützen Sie die Datei vor unbefugtem Zugriff und halten Sie sie aus Git-Repositories heraus:
$ chmod 600 /opt/tooljet/.env
$ echo ".env" >> /opt/tooljet/.gitignoreDie Datei existiert, die Rechte stimmen und kein Secret ist leer:
$ ls -la /opt/tooljet/.env# Erwartete Ausgabe: -rw------- 1 root root ... .env
# Alle Pflicht-Variablen auf Inhalt prüfen:$ grep -E "^(SECRET_KEY_BASE|LOCKBOX_MASTER_KEY|PGRST_JWT_SECRET)=" /opt/tooljet/.envSchritt 3: compose.yaml erstellen
Der Stack besteht aus tooljet (App und Frontend), postgres (Datenbank) und postgrest (interner REST-Layer für die ToolJet-Datenbank).
Zum Image: tooljet/tooljet-ce ist die Community Edition unter AGPL-3.0, tooljet/tooljet die Enterprise Edition mit SAML SSO und Audit-Logs. Die Anleitung legt das Image auf die LTS-Version v3.20.236-lts fest; gleitende Tags wie ce-lts-latest oder latest ziehen bei jedem Pull unkontrolliert neue Versionen.
Erstellen Sie die Datei /opt/tooljet/compose.yaml:
services:
tooljet:
image: tooljet/tooljet-ce:v3.20.236-lts
platform: linux/amd64
restart: always
tty: true
stdin_open: true
ports:
- "3000:80"
env_file:
- .env
environment:
SERVE_CLIENT: "true"
PORT: "80"
command: npm run start:prod
depends_on:
postgres:
condition: service_healthy
volumes:
- logs:/app/logs
- certs:/app/certs
- fallbackcerts:/app/fallbackcerts
postgres:
image: postgres:16
restart: always
environment:
POSTGRES_USER: ${PG_USER}
POSTGRES_PASSWORD: ${PG_PASS}
POSTGRES_DB: ${PG_DB}
volumes:
- ./postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${PG_USER} -d ${PG_DB}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
postgrest:
image: postgrest/postgrest:v12.0.2
platform: linux/amd64
restart: always
environment:
PGRST_DB_URI: ${PGRST_DB_URI}
PGRST_JWT_SECRET: ${PGRST_JWT_SECRET}
PGRST_SERVER_PORT: "80"
PGRST_DB_PRE_CONFIG: postgrest.pre_config
depends_on:
postgres:
condition: service_healthy
volumes:
logs:
certs:
fallbackcerts:Beachte: Der postgres_data-Ordner wird als Bind-Mount (./postgres_data:/var/lib/postgresql/data) und nicht als Named Volume eingebunden. So liegen die Daten sichtbar im Projektordner und bleiben auch bei einem versehentlichen docker compose down -v erhalten.
Die Eckdaten im Überblick:
| Parameter | Wert | Hinweis |
|---|---|---|
| Image (CE) | tooljet/tooljet-ce:v3.20.236-lts | Community Edition, AGPL-3.0 |
| Image (EE) | tooljet/tooljet:ee-lts-latest | Enterprise Edition |
| Stabile Version | v3.20.236-lts | LTS-Version, in dieser Anleitung festgelegt |
| Architektur | linux/amd64 only | ARM64 nicht unterstützt |
| Port (extern) | 3000 → intern 80 | Web-UI und API |
| PostgreSQL | postgres:16 | Bind-Mount ./postgres_data |
| PostgREST | postgrest/postgrest:v12.0.2 | nur container-intern |
| Mindest-RAM | 2 GB (Hersteller) | Mit Datenbank empfohlen: 4 GB |
| Image-Größe | ca. 1,6 GB | Ersten Pull einplanen |
Prüfen Sie die Syntax der compose.yaml vor dem Start:
$ cd /opt/tooljet
$ docker compose config --quiet && echo "Syntax OK"# Erwartete Ausgabe: Syntax OKSchritt 4: Stack starten
Starten Sie den Stack im Hintergrund; der erste Pull des ToolJet-Images dauert einige Minuten:
$ cd /opt/tooljet
$ docker compose up -dBeim allerersten Start führt ToolJet automatisch alle Datenbankmigrationen durch. Dieser Prozess dauert 5 bis 10 Minuten. Starten Sie den Container in dieser Zeit nicht neu, sonst brechen die Migrationen ab. Den Fortschritt zeigen die Logs:
$ docker compose logs -f tooljet# ToolJet ist bereit, wenn die folgende Zeile erscheint (sinngemäß):
# Server is listening on port 80Alle drei Container zeigen Up, PostgreSQL zusätzlich (healthy):
$ docker compose ps# Erwartete Ausgabe:
# NAME IMAGE STATUS
# tooljet-tooljet-1 tooljet/tooljet-ce:v3.20.236-lts Up X minutes
# tooljet-postgres-1 postgres:16 Up X minutes (healthy)
# tooljet-postgrest-1 postgrest/postgrest:v12.0.2 Up X minutesPrüfen Sie zusätzlich, ob ToolJet antwortet:
$ curl -I http://localhost:3000# Erwartete Ausgabe: HTTP/1.1 200 OK (oder 302 Found zur Login-Seite)Schritt 5: Erst-Einrichtung im Browser
Öffnen Sie http://<IHRE-IP>:3000 im Browser. Beim ersten Aufruf legen Sie im Einrichtungsassistenten das erste Admin-Konto an. Anschließend stehen im Dashboard folgende Funktionen bereit:
- Apps erstellen: per Drag-and-Drop im visuellen App-Builder
- Datenquellen verbinden: über „Data Sources“ im linken Menü (PostgreSQL, REST-API, MySQL, MongoDB, S3, Stripe und 75+ weitere)
- Nutzer einladen: über „Settings → Users“ (setzt SMTP-Konfiguration voraus)
- Workspaces verwalten: mehrere getrennte Arbeitsbereiche
Mit DISABLE_SIGNUPS=true registrieren sich neue Benutzer nur noch per Einladung; das ist für produktive Installationen der richtige Ansatz.
Nach dem Anlegen des Admin-Kontos erscheint das leere Dashboard, und die Logs zeigen keine Fehler:
$ docker compose logs --tail=20 tooljet# Keine Zeilen mit ERROR oder FATAL sollten erscheinenSchritt 6: Reverse Proxy und HTTPS (optional, empfohlen)
Für den Produktivbetrieb gehört ToolJet hinter einen Reverse Proxy mit HTTPS. Passen Sie dazu die .env an:
TOOLJET_HOST=https://tooljet.ihre-domain.deBinden Sie den ToolJet-Port nur an Localhost:
ports:
- "127.0.0.1:3000:80"Der Reverse Proxy muss WebSocket-Verbindungen weiterleiten (Upgrade- und Connection-Header), sonst funktionieren Echtzeit-Features in der UI nicht. Eine Einstiegsanleitung bietet Caddy als Reverse Proxy mit automatischem HTTPS; Caddy bezieht Let's-Encrypt-Zertifikate automatisch und leitet WebSockets ohne Zusatzkonfiguration weiter.
Erstellen Sie nach jeder Änderung an der .env den Container neu:
$ docker compose up -d --force-recreate tooljetcurl -I https://tooljet.ihre-domain.de liefert 200 ohne Zertifikatsfehler, ToolJet leitet nicht auf http:// um, und der App-Builder öffnet sich ohne Verbindungsfehler (WebSockets).
Schritt 7: Updates und Backup
Legen Sie vor jedem Update ein Backup beider Datenbanken an:
$ cd /opt/tooljet
$ docker compose exec -T postgres pg_dump -U tooljet tooljet_production > backup_app_$(date +%Y%m%d).sql
$ docker compose exec -T postgres pg_dump -U tooljet tooljet_db > backup_tjdb_$(date +%Y%m%d).sqlFür das Update tragen Sie das neue LTS-Tag aus Docker Hub in die compose.yaml ein; die Migrationen laufen beim Start automatisch:
$ docker compose pull
$ docker compose up -dAlternativ sichern Sie das Verzeichnis postgres_data bei gestopptem Stack. Automatisierte Offsite-Backups mit pg_dump und rclone beschreibt die Anleitung MySQL & PostgreSQL Backup automatisieren mit cron.
ls -lh backup_*.sql zeigt zwei nicht leere Dumps, docker compose images das neue Tag, und docker compose ps alle drei Container als Up.
Troubleshooting / Typische Fehler
- Container startet nicht, postgres_data-Fehler
Tritt mit der Herstellervorlage auf, die den Ordner als Bind-Volume (
driver_opts) einbindet und ihn nicht selbst anlegt. Ordner anlegen (mkdir /opt/tooljet/postgres_data) unddocker compose up -derneut ausführen.- OAuth/SAML-Redirect schlägt fehl, falsche Weiterleitungs-URL
TOOLJET_HOSTist ohne Protokoll gesetzt oder zeigt auf die falsche IP. Immerhttp://oderhttps://voranstellen und die korrekte öffentlich erreichbare Adresse verwenden. Nach Änderungdocker compose up -d --force-recreate tooljet.- Kryptofehler beim Start / App zeigt leere Seite
SECRET_KEY_BASEoderLOCKBOX_MASTER_KEYsind leer oder wurden nachträglich geändert. Bei bestehenden Daten nicht mehr ändern. Prüfen mitdocker compose exec tooljet env | grep SECRET_KEY_BASE.- PostgREST crasht in Schleife
PGRST_DB_URIzeigt auf falsche Datenbank oder Zugangsdaten stimmen nicht. URI-Format prüfen:postgres://tooljet:passwort@postgres:5432/tooljet_db. PostgreSQL-Healthcheck abwarten.- Container startet nicht auf ARM64 / Apple Silicon (Exec format error)
ToolJet unterstützt offiziell nur
linux/amd64. Auf Apple Silicon hilftplatform: linux/amd64(Emulation) nur für Tests.- Sehr langsamer erster Start (5 bis 10 Minuten)
Normal, die Migrationen laufen. Logs beobachten, nicht neu starten.
- E-Mail-Einladungen kommen nicht an
SMTP-Variablen fehlen in der
.env.DEFAULT_FROM_EMAIL,SMTP_DOMAIN,SMTP_PORT,SMTP_USERNAMEundSMTP_PASSWORDeintragen und Stack neu starten.- Workflows funktionieren nicht bei mehreren Instanzen
Workflows benötigen bei mehreren Worker-Instanzen einen externen Redis. Einen Redis-Container hinzufügen und
REDIS_HOST/REDIS_PORTin der.envsetzen.- .env versehentlich committed
Aus dem Repository-Verlauf entfernen,
PGRST_JWT_SECRETund Datenbankpasswort ersetzen; beiLOCKBOX_MASTER_KEYundSECRET_KEY_BASEvorher gespeicherte Zugangsdaten sichern, da ein Wechsel sie ungültig macht.
Häufige Fragen
Welchen Image-Tag soll ich verwenden: ce-lts-latest, ee-lts-latest oder latest?
Für den Open-Source-Betrieb tooljet/tooljet-ce, für Enterprise-Features wie SAML SSO oder Audit-Log tooljet/tooljet (proprietäre Lizenzteile). In beiden Fällen ein festes LTS-Tag wie v3.20.236-lts verwenden; ce-lts-latest und latest lösen bei jedem Pull ungeplante Updates und Migrationen aus.
Wie groß sind die Systemanforderungen wirklich?
Der Hersteller nennt 1 vCPU, 2 GB RAM und 8 GiB Speicher für eine VM, x86-64, Ubuntu 22.04 oder neuer. Mit PostgreSQL und PostgREST auf demselben Host sind 2 vCPUs und 4 GB RAM eine sinnvolle Größe für ein kleines Team.
Kann ich ToolJet hinter einem Reverse Proxy mit HTTPS betreiben?
Ja, das ist der empfohlene Weg; die Einstellungen stehen in Schritt 6. Wichtig ist die WebSocket-Weiterleitung, sonst funktioniert der App-Builder nicht korrekt.
Was ist der Unterschied zwischen ToolJet DB und der PostgreSQL-Datenbank?
ToolJet nutzt PostgreSQL als App-Datenbank (Konfiguration, Apps, Benutzer) und als ToolJet DB: eine integrierte Datenbank, in der Sie direkt aus ToolJet-Apps Tabellen anlegen und abfragen, ohne eine externe Datenquelle zu konfigurieren. PostgREST stellt diese zweite Datenbank per REST bereit.
Wie deaktiviere ich die öffentliche Registrierung?
DISABLE_SIGNUPS=true in der .env setzen und den Container mit docker compose up -d --force-recreate tooljet neu erstellen. Danach registrieren sich neue Nutzer nur per Einladung.
Wie sichere ich die Daten bei einem Update ab?
Mit den beiden pg_dump-Befehlen aus Schritt 7 oder bei gestopptem Stack per rsync auf ./postgres_data. Verwenden Sie nie docker compose down -v; das Flag löscht die Named Volumes.
Fazit
ToolJet liefert interne Admin-Panels, CRUD-Oberflächen und Dashboards mit wenig eigenem Code, weil über 80 Konnektoren die Anbindung übernehmen. Die Installation dauert etwa 30 Minuten; entscheidend sind die drei Secrets und ein korrektes TOOLJET_HOST. Gegenüber Retool bleiben die Daten auf Ihrem Server. Einschränkungen: keine ARM-Unterstützung und ein langer erster Start. Für den Produktivbetrieb gehören Reverse Proxy mit HTTPS und automatische pg_dump-Backups dazu.
Eine Alternative mit ähnlichem Ansatz ist Appsmith mit Docker. Zur Härtung des Stacks: Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only für den Produktivbetrieb.
Weiterführende Anleitungen und Quellen
- Docker und Docker Compose auf Linux installieren (Ubuntu/Debian): die Self-Hosting-Grundlage
- Caddy als Reverse Proxy einrichten: Anfänger-Anleitung mit automatischem HTTPS
- MySQL & PostgreSQL Backup automatisieren mit cron: mysqldump, pg_dump, Rotation und rclone-Cloud-Sync
- Appsmith mit Docker installieren: Open-Source Low-Code für interne Tools
- Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only für den Produktivbetrieb
Offizielle Quellen: ToolJet Docs: Deploying with Docker Compose | ToolJet GitHub Repository | ToolJet Environment Variables Reference | Docker Hub: tooljet/tooljet-ce


