Deployn

Excaliself installieren: Excalidraw als Team-Whiteboard auf dem eigenen Server

Excaliself mit Docker Compose und Caddy auf einem Debian-13-Server installieren und Funktionen wie Live-Zusammenarbeit, Ordner und Einladungen kennenlernen

Excaliself installieren: Excalidraw als Team-Whiteboard auf dem eigenen Server hero image
Inhalt
Getestet mit
Excaliself 0.11.1Caddy 2.11Docker 29.9Debian 13
Zuletzt geprüft am

Excalidraw ist ein virtuelles Whiteboard, auf dem Zeichnungen aussehen wie von Hand skizziert. Excaliself packt den Excalidraw-Editor in eine kleine App für den eigenen Server: mit Benutzerkonten, Ordnern, Suche, einem gemeinsamen Team-Bereich und Live-Zusammenarbeit. Alle Zeichnungen landen in einer eigenen Postgres-Datenbank. In dieser Anleitung installiere ich Excaliself mit Docker Compose und Caddy auf einem Debian-Server und zeige die wichtigsten Funktionen.

Was ist Excaliself?

Excaliself ist ein Open-Source-Projekt unter MIT-Lizenz, das auf GitHub unter maciekzygmunt/excaliself liegt. Der Editor selbst ist das Paket @excalidraw/excalidraw, das auch auf excalidraw.com steckt. Excaliself ergänzt, was dort fehlt, wenn ein Team damit arbeiten will:

  • Konten und Einladungen. Den ersten Nutzer legst du beim ersten Aufruf als Admin an. Alle weiteren kommen über Einladungslinks.
  • Privater Bereich und Team-Bereich. Jedes Mitglied hat eigene Zeichnungen. Daneben gibt es einen gemeinsamen Team-Bereich, den alle sehen und bearbeiten.
  • Live-Zusammenarbeit mit Cursorn der anderen Teilnehmer, per Link auch für Gäste ohne Konto.
  • Ordner, Favoriten, Suche und Papierkorb. Die Suche findet auch Text innerhalb von Zeichnungen. Gelöschte Zeichnungen bleiben 30 Tage im Papierkorb.
  • Team-Bibliothek mit Formen und Icons, die für alle gilt. Bibliotheken von libraries.excalidraw.com lassen sich einspielen.
  • Single Sign-on mit Google Workspace, Microsoft Entra ID oder jedem OIDC-Anbieter wie Authentik oder Keycloak.
  • MCP-Server. KI-Clients wie Claude Code können Zeichnungen lesen, anlegen und Änderungen vorschlagen. Die Instanz braucht dafür keinen eigenen API-Key für ein Sprachmodell.

Glossar

Begriff Beschreibung
Excalidraw Das Whiteboard mit dem handgezeichneten Look. Excaliself verwendet dessen Editor.
Reverse Proxy Ein Programm vor der App, das Anfragen aus dem Internet annimmt und weiterreicht. Hier ist das Caddy.
Caddy Ein Webserver, der HTTPS-Zertifikate bei Let’s Encrypt automatisch besorgt und erneuert.
Docker Compose Startet mehrere Container (hier App und Datenbank) mit einer einzigen Datei und einem Befehl.
A-Record Ein DNS-Eintrag, der einen Domainnamen auf eine IPv4-Adresse zeigen lässt.
MCP Model Context Protocol, eine Schnittstelle, über die KI-Clients Werkzeuge einer Anwendung nutzen können.

Voraussetzungen

  1. Ein Server mit Debian 13. Ich nutze einen VPS bei Hetzner mit 2 vCPU und 4 GB RAM. Die App ist genügsam: Im Leerlauf belegten App und Datenbank zusammen etwa 105 MB. Das Image der App ist 362 MB groß, das von Postgres 424 MB, plane also etwas Platz auf der Platte ein. Wenn du noch keinen Server hast, hilft dir mein VPS-Leitfaden für Anfänger.
  2. Eine Domain oder Subdomain, deren A-Record auf die IP deines Servers zeigt. Ich nutze {{domain}}.
  3. Offene Ports 80 und 443.

Prüfe vorher, ob der DNS-Eintrag stimmt. Auf deinem Rechner:

Terminalbash
dig +short {{domain}}

Die Ausgabe muss die IP deines Servers sein. Danach meldest du dich per SSH als root an:

Terminalbash
ssh root@{{domain}}

Schritt 1: Docker installieren

Docker installierst du mit dem offiziellen Skript:

Terminalbash
apt update && apt install -y curl ca-certificates
curl -fsSL https://get.docker.com | sh

Zur Kontrolle:

Terminalbash
docker --version
docker compose version
Docker version 29.9.3, build 5457199
Docker Compose version v5.7.1

Schritt 2: Caddy installieren

Caddy muss installiert werden. Beispielsweise wie in diesem Blogpost beschrieben.

Schritt 3: Excaliself herunterladen und konfigurieren

Wir legen einen Ordner an und laden die Compose-Datei und eine Vorlage für die Einstellungen aus dem Repository:

Terminalbash
mkdir -p /opt/excaliself && cd /opt/excaliself
curl -fsSLO https://raw.githubusercontent.com/maciekzygmunt/excaliself/main/docker-compose.yaml
curl -fsSL -o .env https://raw.githubusercontent.com/maciekzygmunt/excaliself/main/.env.example

Die docker-compose.yaml startet zwei Container: die App (ghcr.io/maciekzygmunt/excaliself) und Postgres 17. Das Image ist fertig gebaut, auf dem Server wird nichts kompiliert.

In der .env fehlen drei Dinge: zwei Geheimnisse und die öffentliche Adresse. Erzeuge zuerst die Geheimnisse:

Terminalbash
openssl rand -hex 24
openssl rand -base64 32

Die erste Ausgabe ist das Passwort der Datenbank, die zweite der Schlüssel, mit dem die App Sitzungen signiert. Das Datenbank-Passwort muss aus Hex-Zeichen bestehen, weil es in eine Verbindungs-URL eingebaut wird. Darum der Befehl mit -hex. Öffne die Datei:

Terminalbash
nano .env

Trage die Werte ein:

ini
POSTGRES_PASSWORD=HIER-DIE-ERSTE-AUSGABE
BETTER_AUTH_SECRET=HIER-DIE-ZWEITE-AUSGABE
BASE_URL=https://{{domain}}
EXCALISELF_PORT=127.0.0.1:3000

EXCALISELF_PORT steht in der Vorlage auskommentiert mit # davor. Entferne das #. Mit 127.0.0.1:3000 ist die App nur vom Server selbst erreichbar. Von außen kommt man ausschließlich über Caddy hinein, und das ist gewollt, denn dort sitzt das HTTPS.

BASE_URL muss exakt die Adresse sein, die du im Browser eingibst. Die App lehnt Anmeldungen von jeder anderen Adresse ab. Speichern in nano mit Strg+O, Enter, Strg+X.

Schritt 4: Caddy auf die Domain einrichten

Die Konfiguration von Caddy liegt in /etc/caddy/Caddyfile. Ersetze den Inhalt durch:

{{domain}} {
    reverse_proxy 127.0.0.1:3000
}

Das heißt: Alles, was an {{domain}} ankommt, geht an die App auf Port 3000. Das Zertifikat holt Caddy selbst. Die Konfiguration lädst du neu und startest dann Excaliself:

Terminalbash
systemctl reload caddy
cd /opt/excaliself
docker compose up -d

Beim ersten Mal lädt Docker die Images herunter, das dauert eine Minute. Danach zeigt docker compose ps beide Container:

Terminalbash
docker compose ps --format "{{.Name}} {{.Status}}"
excaliself-db-1 Up 10 seconds (healthy)
excaliself-excaliself-1 Up 4 seconds (health: starting)

Die App meldet sich über /api/health. Der Aufruf liefert 200, wenn sie läuft und die Datenbank erreicht:

Terminalbash
curl https://{{domain}}/api/health
{"status":"ok"}

Die Datenbank-Migrationen laufen beim Start automatisch.

Schritt 5: Den Admin anlegen

Öffne https://{{domain}} im Browser. Du landest auf /setup. Dort legst du den Admin-Account mit E-Mail-Adresse und Passwort an.

Die Einrichtungsseite von Excaliself

Solange kein Admin existiert, kann jeder, der die Adresse aufruft, den ersten Account anlegen. Erledige diesen Schritt deshalb direkt nach docker compose up -d.

Danach führt dich die App durch eine kurze Tour mit drei Hinweisen: die Suche, das Anlegen einer Zeichnung und das Teilen.

Die Funktionen im Überblick

Zeichnen

Mit N oder dem Button „New drawing” legst du eine Zeichnung an. Du gibst ihr einen Namen, und der Editor öffnet sich. Er ist der normale Excalidraw-Editor: Rechtecke (R), Pfeile (A), Text (Doppelklick in eine Form), Freihand und eine Bibliothek. Gespeichert wird automatisch, unten rechts steht „Saved”.

Der Editor mit einer einfachen Zeichnung aus zwei Kästen und einem Pfeil

Links in der Seitenleiste liegen Startseite, alle Zeichnungen, die Ordner und der Papierkorb. Unter „Drawings” kannst du Ordner anlegen und Zeichnungen per Drag-and-drop verschieben. Mit ⌘K oder Strg+K öffnest du die Suche, die Titel und Text in Zeichnungen durchsucht und auch Befehle ausführt.

Zusammen arbeiten und teilen

Der Button mit dem Teilen-Symbol öffnet ein Fenster. Dort wählst du, wer den Link nutzen darf:

  • Members of this instance: Besucher müssen angemeldet sein.
  • Anyone with the link: Auch Gäste ohne Konto können mitzeichnen und suchen sich einen Anzeigenamen aus.

Der Dialog zum Teilen einer Zeichnung

Ein Klick auf „Create share link” erzeugt den Link. Alle, die ihn öffnen, sehen die Cursor der anderen und die Änderungen sofort. Zeichnungen im Team-Bereich sind immer live.

Mitglieder einladen

Weitere Nutzer legst du nicht selbst an. Unter Einstellungen → Invites erzeugst du einen Link mit „Generate link”. Der Link gilt für ein Mitglied und läuft nach sieben Tagen ab. Du schickst ihn an die Person, die beitreten soll. Unter Members änderst du Rollen und legst Links für das Zurücksetzen von Passwörtern an.

Die Einstellungsseite für Einladungslinks

KI-Clients über MCP verbinden

Unter Einstellungen → MCP erzeugst du Zugriffstoken. Mit einem Token kann ein KI-Client wie Claude Code Zeichnungen suchen, lesen, anlegen und Änderungen vorschlagen. Eine Änderung an einer bestehenden Zeichnung passiert erst, wenn du im Editor auf „Apply” klickst. Löschen kann der Client nichts endgültig, Gelöschtes landet im Papierkorb.

Die MCP-Einstellungen mit Zugriffstoken und verbundenen Apps

Der Server hört auf https://{{domain}}/api/mcp. In Claude Code verbindest du ihn mit diesem Befehl. Das Token bekommst du nur einmal beim Anlegen angezeigt:

Terminalbash
claude mcp add --transport http excaliself https://{{domain}}/api/mcp \
  --header "Authorization: Bearer exs_DEIN-TOKEN"

Claude.ai nutzt OAuth ohne Token, dafür muss die Instanz aus dem Internet über HTTPS erreichbar sein. Dort fügst du unter Einstellungen → Konnektoren einen eigenen Konnektor mit derselben URL hinzu.

Weitere Funktionen

  • Import aus Excalidraw+ (Beta) unter Einstellungen → Import, mit einem API-Key von Excalidraw+.
  • Dateien hineinziehen: .excalidraw-Dateien oder PNG- und SVG-Exporte mit eingebetteter Szene lassen sich auf einen Ordner in der Seitenleiste ziehen.
  • Single Sign-on richtest du über Umgebungsvariablen in der .env ein, etwa OIDC_ISSUER, OIDC_CLIENT_ID und OIDC_CLIENT_SECRET. Mit SSO_ALLOWED_DOMAINS bestimmst du, welche E-Mail-Domains sich ohne Einladung anmelden dürfen.
  • Themes: hell, dunkel oder nach Systemeinstellung, auf Wunsch mit eigenem Theme für die Zeichenfläche.

Auf der Seite Instance siehst du Version, Anzahl der Nutzer und Zeichnungen und den belegten Speicher.

Die Instanz-Seite mit Version 0.11.1

Excaliself unter einem Unterverzeichnis: geht das?

Manche wollen nicht für jede App eine eigene Subdomain, sondern lieber meinedomain.de/draw. Bei Excaliself klappt das nicht.

Der übliche Weg bei Caddy ist handle_path. Es entfernt das Präfix, bevor die Anfrage an die App geht:

{{domain}} {
    handle_path /whiteboard/* {
        reverse_proxy 127.0.0.1:3000
    }
}

Jedoch gibt es hier zwei Probleme.

  1. Die App schreibt absolute Pfade in das HTML. Ein Blick in die Login-Seite zeigt, dass Stylesheet und Skripte von /assets/… geladen werden:

    Terminalbash
    curl -s http://127.0.0.1:3000/login | grep -o -E 'href="[^"]+"' | head -3
    href="/assets/styles-CdofQDSL.css"
    href="/assets/index-NmK34gBZ.js"
    href="/assets/rolldown-runtime-Dd_uD5pT.js"

    Der Browser fragt {{domain}}/assets/… an, nicht {{domain}}/whiteboard/assets/…. Dort liegt in der Caddy-Konfiguration nichts, also kommt nichts an.

  2. Der Router der App kennt kein Präfix. Beim Aufruf von /whiteboard/ springt der Client direkt auf /draw, die Startseite der App. Diesen Pfad leitet Caddy in diesem Aufbau nicht weiter.

Auch ohne Prefix-Strip, also mit handle /whiteboard/* statt handle_path, klappt es nicht. Dann bekommt die App /whiteboard/login und /whiteboard/api/health und antwortet mit 404, weil sie diese Pfade nicht kennt.

Einen Schalter für einen Basis-Pfad gibt es in der Konfiguration nicht.

Backup

Alle Daten liegen in der Postgres-Datenbank: Konten, Zeichnungen, Bilder und Freigabelinks. Ein Dump sichert die ganze Instanz. Im Ordner mit der docker-compose.yaml:

Terminalbash
docker compose exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" -Fc "$POSTGRES_DB"' > excaliself-$(date +%F).dump

Sichere außerdem die .env. Ohne sie lässt sich die Instanz nicht wiederherstellen. Kopiere beides auf einen anderen Rechner. Zum Zurückspielen stoppst du die App und lädst den Dump ein:

Terminalbash
docker compose stop excaliself
docker compose exec -T db sh -c 'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists' < excaliself-2026-11-11.dump
docker compose start excaliself

Das ersetzt die aktuellen Daten.

Excaliself aktualisieren

Terminalbash
cd /opt/excaliself
docker compose pull
docker compose up -d

Die App spielt die Datenbank-Migrationen beim Start ein. Es gibt keine Migrationen rückwärts. Mach deshalb vor jedem Update einen Dump, denn nur damit kommst du zur älteren Version zurück. Möchtest du bestimmte Versionen festhalten, setzt du in der .env EXCALISELF_VERSION=0.11.1. Mit latest bekommst du immer die neueste Version, main ist der unveröffentlichte Stand.

Probleme und Lösungen

Problem Ursache und Lösung
docker compose up bricht mit „Set POSTGRES_PASSWORD” ab Ein Pflichtwert in der .env fehlt. POSTGRES_PASSWORD und BETTER_AUTH_SECRET eintragen.
Anmeldung schlägt fehl BASE_URL stimmt nicht mit der Adresse im Browser überein, etwa http statt https oder eine andere Domain.
Zertifikat wird nicht ausgestellt Der A-Record zeigt nicht auf den Server, oder Port 80 und 443 sind gesperrt. Logs mit journalctl -u caddy prüfen.
Live-Zusammenarbeit funktioniert nicht Der Reverse Proxy leitet WebSockets unter /ws/ nicht durch. Caddy tut das ohne weitere Einstellung.
Bilder lassen sich bei nginx nicht hochladen Das Standardlimit von 1 MB für Anfragen ist zu klein. In nginx client_max_body_size 32m; setzen.

Fazit

Die Installation besteht aus Docker, Caddy und vier Werten in der .env, und die Zeichnungen liegen auf deinem eigenen Server. Der Editor ist der vertraute von excalidraw.com, die App drumherum bringt Konten, Ordner, Suche und Live-Zusammenarbeit mit.

Nutzt du schon ein selbst gehostetes Whiteboard? Schreib mir gern in die Kommentare, was du dort nutzt.

FAQ

Häufige Fragen

Was ist der Unterschied zwischen Excaliself und Excalidraw?

Excalidraw ist der Zeichen-Editor, den du auch auf excalidraw.com findest. Excaliself nutzt diesen Editor und ergänzt Benutzerkonten, Ordner, Suche, einen Team-Bereich, Live-Zusammenarbeit und eine Datenbank auf deinem Server, in der alle Zeichnungen liegen.

Läuft Excaliself unter einem Unterverzeichnis wie meinedomain.de/draw?

Nein. Die App liefert absolute Pfade wie /assets/… aus und hat keine Einstellung für einen Basis-Pfad. Mit Caddy und handle_path bleibt die Seite leer. Verwende eine Subdomain wie draw.meinedomain.de.

Wie viel RAM braucht Excaliself?

Im Leerlauf belegten die App etwa 65 MB und Postgres etwa 40 MB. Auf einem Server mit 2 GB RAM ist also genug Platz. Das Image der App ist 362 MB groß, das von Postgres 424 MB.

Kann ich Excaliself ohne Domain nutzen?

Lokal zum Ausprobieren ja, mit dem Befehl aus dem README: docker run --rm -p 127.0.0.1:3000:3000 -e PREVIEW_MODE=true ghcr.io/maciekzygmunt/excaliself. Die Daten sind nach dem Stoppen weg. Für einen echten Betrieb brauchst du eine Domain mit HTTPS, weil die Anmeldung nur von der Adresse in BASE_URL akzeptiert wird.

Wie lege ich weitere Benutzer an?

Unter Einstellungen → Invites erzeugst du einen Einladungslink. Er gilt für ein Mitglied und läuft nach sieben Tagen ab. Alternativ melden sich Personen mit einer erlaubten E-Mail-Domain über Single Sign-on an.

Wo liegen die Zeichnungen und wie sichere ich sie?

Alles liegt in der Postgres-Datenbank im Docker-Volume pgdata. Mit pg_dump im db-Container erzeugst du ein Backup. Sichere zusätzlich die Datei .env und kopiere beides auf einen anderen Rechner.

Kann ich Excaliself mit Claude oder anderen KI-Clients nutzen?

Ja. Excaliself hat einen MCP-Server unter /api/mcp. Claude.ai verbindest du über OAuth, Claude Code und andere Clients mit einem Zugriffstoken aus den Einstellungen. Änderungen an Zeichnungen schlägt der Client nur vor, sie gelten erst, wenn du im Editor auf Apply klickst.