Excalidraw is an open-source virtual whiteboard for hand-drawn-style diagrams: architecture sketches, flowcharts, wireframes and brainstorming. Its look is deliberately informal, which makes diagrams quick to draw and easy to read. The app runs entirely in the browser, so self-hosting is simple: a static web app, plus an optional small server for live collaboration.
Why self-host it?
- Keep diagrams of internal systems on your own infrastructure.
- Work offline or inside a private network.
- Customise the deployment, for example with a company domain, or behind SSO.
What the pieces are
| Component | Role | Needed? |
|---|---|---|
| excalidraw (static app) | The whiteboard itself; saves to browser storage and exports files | Yes |
| excalidraw-room | WebSocket server for real-time collaboration | Only for live collaboration |
| Storage backend | Saving shared scenes and share links | Optional (the public site uses its own) |
Without a room server, everyone can still draw, save .excalidraw files, and export PNG/SVG. Real-time collaboration needs the room server.
Run the app with Docker
# /opt/excalidraw/compose.yaml
services:
excalidraw:
image: excalidraw/excalidraw:latest
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
cd /opt/excalidraw && docker compose up -d
Or build the static files yourself from the repository (yarn build) and serve the build/ directory with Nginx. See deploying a static site.
Nginx with HTTPS
server {
server_name draw.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
}
# listen 443 ssl; certbot --nginx -d draw.example.com
}
See Let’s Encrypt.
Live collaboration
Add the room server:
excalidraw-room:
image: excalidraw/excalidraw-room:latest
restart: unless-stopped
ports:
- "127.0.0.1:3002:80"
Proxy it with WebSocket support (for example on collab.example.com):
server {
server_name collab.example.com;
location / {
proxy_pass http://127.0.0.1:3002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
The official frontend image is built to use the public collaboration servers. To point it at your room server, build the app with the environment variable for the WebSocket server URL set to https://collab.example.com (check the repository’s .env files for the current variable names). Session content is end-to-end encrypted between participants: the key is in the link fragment, and the room server only relays ciphertext. See Nginx WebSocket proxy.
Storage and sharing
- Local: the scene autosaves to the browser’s local storage.
- Files: save and open
.excalidrawfiles (JSON). Keep important diagrams in Git or a shared drive, such as Nextcloud. - Export: PNG or SVG, optionally with the scene embedded, so you can re-open and edit the image later.
- “Shareable links” in the hosted service rely on Excalidraw’s own storage backend. Community forks and wrappers add self-hosted storage if you need it.
Libraries and integrations
- Load libraries (shapes for AWS, Kubernetes, UI wireframes and more) from libraries.excalidraw.com, or import
.excalidrawlibfiles. - Excalidraw is embedded in many tools: Obsidian’s Excalidraw plugin, Nextcloud Whiteboard, and others.
- Mermaid to Excalidraw: paste Mermaid syntax to generate an editable diagram.
Access control
The static app has no logins. If it should be internal only, add basic auth, SSO, or a VPN in front. See Nginx basic auth and Tailscale.
Updates
docker compose pull && docker compose up -d, or rebuild from the latest release if you build your own image. See updating self-hosted apps.
Quick reference
| Item | Value |
|---|---|
| App image | excalidraw/excalidraw (static, port 80) |
| Collaboration | excalidraw/excalidraw-room (WebSockets) |
| File format | .excalidraw (JSON) |
| Exports | PNG, SVG (scene can be embedded) |
| Access control | Nginx basic auth / SSO / VPN |
Related: Outline wiki and Wiki.js.