Excalidraw

Excalidraw

Docker app from junkerderprovinz's Repository

Overview

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. What that means in practice: • Shared links are stored in this container, not on json.excalidraw.com • A live session keeps its scene here, not in Google Firestore • Pasted images stay here, not in Firebase Storage • The collaboration socket is this container, not oss-collab.excalidraw.com • Fonts are served from the image, and the analytics script is gone • Everything 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 Two features would still talk to Excalidraw's servers, so they are switches rather than a decision made for you, and both are OFF by default: the shape library and the text-to-diagram feature. Off means the request never leaves your server. Notes: • Use the HTTPS port. Live collaboration needs crypto.subtle, which browsers only provide over HTTPS, so on the plain HTTP port the "start 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 is there for a reverse proxy that terminates TLS, and for the single-user case where no session is ever started. • Behind a reverse proxy: allow WebSocket upgrades on /socket.io/ and a body size of 64 MB, otherwise collaboration cannot connect and drawings with images are refused. • /config holds the drawings database and the certificate. Back it up and you have backed up everything.

excalidraw

Build  Lint  Docker Pulls  Image Size  Arch  Go  nginx  Unraid  License: AGPL-3.0


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.


Buy me a coffee


Table of Contents

  1. What is this?
  2. Screenshots
  3. What it keeps off the internet
  4. How it is built
  5. Quick Start on Unraid
  6. Configuration
  7. Reverse Proxy
  8. Building it yourself
  9. Updating Excalidraw
  10. License
  11. 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

A diagram on the canvas
The whiteboard itself, unchanged: this is Excalidraw, drawing the way it always does.

The share dialog
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

Buy me a coffee

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.

Open the Apps tab on your Unraid server Search Community Apps for Excalidraw Review the template variables and paths Click Install

Download Statistics

141
Total Downloads

Related apps

Details

Repository
junkerderprovinz/excalidraw:latest
Last Updated2026-09-05
First Seen2026-09-05

Runtime arguments

Web UI
https://[IP]:[PORT:443]/
Network
bridge
Shell
sh
Privileged
false
Extra Params
--restart=unless-stopped

Template configuration

WebUI Port (HTTPS)Porttcp

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
WebUI Port (HTTP)Porttcp

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
AppData (/config)Pathrw

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
Shape libraryVariable

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
Text to diagramVariable

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 zoneVariable

Time zone used for the container log.

Target
TZ
Default
Europe/Berlin
Value
Europe/Berlin