All apps · 0 apps
Excalidraw
Docker app from junkerderprovinz's Repository
Overview
Readme
View on GitHub
Excalidraw is a virtual whiteboard for sketches that look hand-drawn. This is a self-hosted build of it that keeps to itself: shared links, live collaboration, the session scene, the fonts and the icons all come from your own server, and the browser never contacts anyone else. One container, one port, nothing to configure.
Maintained solo, in whatever spare time there is. Questions via the support thread, bugs, ideas and feature requests via GitHub issues. If it's useful to you, a coffee is always welcome.
Table of Contents
- What is this?
- Screenshots
- What it keeps off the internet
- How it is built
- Quick Start on Unraid
- Configuration
- Reverse Proxy
- Building it yourself
- Updating Excalidraw
- License
- Support this project
1. What is this?
Excalidraw is excellent, and the published image of it is a plain web server with the app inside. What that image does not tell you is how much of the app still talks to Excalidraw's own infrastructure: a shared link is stored on their server, a live session keeps its scene in Google Firestore, the fonts come from a CDN, and an analytics script loads on every visit.
None of that is a criticism of the project. It is how a free hosted service pays for itself, and all of it is configurable at BUILD time, which is precisely why the published image cannot offer it as a setting.
This image is that build, done differently. Everything above points back at the container, and a gate in the build refuses to produce an image where any of it still points outward.
2. Screenshots
The whiteboard itself, unchanged: this is Excalidraw, drawing the way it always does.
Both of these now run on your server. The session is end-to-end encrypted, and the key never leaves the link.
3. What it keeps off the internet
| What | Upstream | Here |
|---|---|---|
| Shared links | json.excalidraw.com |
this container, in SQLite |
| Live session scene | Google Firestore | this container, in SQLite |
| Pasted images | Firebase Storage | this container, in SQLite |
| Collaboration socket | oss-collab.excalidraw.com |
this container |
| Fonts | a CDN | this container |
| Analytics | simpleanalyticscdn.com |
removed |
| Shape library | libraries.excalidraw.com |
off by default, switch below |
| Text to diagram | oss-ai.excalidraw.com |
off by default, switch below |
The last two are real features rather than telemetry, so they are switches instead of a decision made for you. Off means the request never leaves your server; the feature reports an error rather than pretending to work.
Everything a drawing contains is encrypted in your browser before it is stored, with the key in
the part of the link after the #, which browsers never send to a server. The container holds
bytes it cannot read.
4. How it is built
Three processes behind one nginx:
- The app, built from a pinned Excalidraw commit with one file replaced, the one that talks to Firestore. Same encryption, same merge logic when two people draw at once, different destination.
- The store, a small Go binary over SQLite, serving the scene, room and file endpoints the app expects. The usual self-hosted store is a Node service whose published image has not been rebuilt since February 2022; this one is built here and tested here.
- The room server, Excalidraw's own relay. It forwards messages between browsers and stores nothing, which is why the store exists.
The addresses in the app are relative paths, not an absolute URL built from a variable you have to set. Your browser resolves them against whatever address you opened, so the same image works on a LAN IP, behind a reverse proxy and under a subdomain with nothing to configure.
5. Quick Start on Unraid
Search for excalidraw in Community Applications, or add the container by hand:
docker run -d \
--name excalidraw \
-p 8080:80 \
-p 8443:443 \
-v /mnt/user/appdata/excalidraw:/config \
--restart unless-stopped \
ghcr.io/junkerderprovinz/excalidraw:latest
Then open https://your-server:8443.
Use the HTTPS port. Live collaboration needs crypto.subtle, which browsers only provide in a
secure context, so over plain HTTP the session button fails with a cryptography error. The
container generates a self-signed certificate on first start and keeps it in /config, so your
browser only has to be told once. The HTTP port stays for the single-user case where no session is
ever started.
6. Configuration
| Variable | Default | What it does |
|---|---|---|
ENABLE_LIBRARY |
false |
Set to true to let the shape library load from libraries.excalidraw.com. |
ENABLE_AI |
false |
Set to true to let the text-to-diagram feature send your text to oss-ai.excalidraw.com. |
STORE_DB |
/config/store.sqlite |
Where drawings, rooms and images are kept. |
TZ |
Etc/UTC |
Time zone for the log. |
/config holds the database and the certificate. Back it up and you have backed up everything.
7. Reverse Proxy
Point your proxy at port 80 of the container and let it terminate TLS. The app only ever uses relative paths, so nothing needs to know its own address. Two things the proxy has to allow:
- WebSocket upgrades on
/socket.io/, or live collaboration cannot connect. - A body size large enough for a drawing with images, 64 MB matches what the container accepts.
8. Building it yourself
git clone https://github.com/junkerderprovinz/excalidraw.git
cd excalidraw
docker build -t excalidraw .
The build takes a while, because it compiles Excalidraw from source. The last step is the gate: it searches the finished app for every address that should be gone and fails the build if it finds one, so an image that calls home cannot be produced by accident.
The Go store has its own tests:
cd backend && go test ./...
9. Updating Excalidraw
The upstream commit is pinned in the Dockerfile as EXCALIDRAW_SHA, deliberately, so the image
does not change under you. To move it forward, set the new commit and rebuild. If the replaced file
has changed upstream, the build fails at the TypeScript step rather than silently shipping a broken
whiteboard, and the gate independently checks that the two switchable addresses are still where the
runtime expects them.
10. License
This repository is licensed under AGPL-3.0 (see LICENSE).
Excalidraw itself is MIT-licensed
and belongs to the Excalidraw team. The two replaced files in frontend/ are derived from theirs
and say so in their headers. This project is not affiliated with or endorsed by Excalidraw.
11. Support this project
Install Excalidraw on Unraid in a few clicks.
Find Excalidraw in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Categories
Download Statistics
Related apps
Explore more like this
Explore allLinks
Details
junkerderprovinz/excalidraw:latestRuntime arguments
- Web UI
https://[IP]:[PORT:443]/- Network
bridge- Shell
sh- Privileged
- false
- Extra Params
--restart=unless-stopped
Template configuration
The port to open in your browser. HTTPS is required for live collaboration, because browsers only provide the cryptography it needs over a secure connection. The certificate is self-signed and generated on first start — accept it once.
- Target
- 443
- Default
- 8443
- Value
- 8443
For a reverse proxy that terminates TLS in front of the container, or for solo drawing where no session is ever started. Live collaboration does NOT work over this port when opened directly in a browser.
- Target
- 80
- Default
- 8080
- Value
- 8080
Holds the drawings database (shared links, live sessions, pasted images) and the self-signed certificate. This is the only thing worth backing up.
- Target
- /config
- Default
- /mnt/user/appdata/excalidraw
- Value
- /mnt/user/appdata/excalidraw
Set to true to allow the shape library to load from libraries.excalidraw.com. That is a public catalogue of drawings other people published, so nothing of yours is sent, but your browser does contact Excalidraw's server. Left false, the library button reports an error and nothing leaves your network.
- Target
- ENABLE_LIBRARY
- Default
- false
- Value
- false
Set to true to allow the text-to-diagram feature, which sends what you typed to Excalidraw's AI service. Left false, the feature reports an error and your text stays here.
- Target
- ENABLE_AI
- Default
- false
- Value
- false
Time zone used for the container log.
- Target
- TZ
- Default
- Europe/Berlin
- Value
- Europe/Berlin