# ExcaliDash: a self-hosted Excalidraw dashboard with scoped sharing

> ExcaliDash wraps Excalidraw in a self-hosted dashboard with persistent storage, version history, live collaboration and optional OIDC. It is beta software, Docker-first, and its README points to separate docs for anything beyond the quickstart.

**ZimengXiong/ExcaliDash** — A self-hosted dashboard and organizer for Excalidraw with multi-user collaboration and scoped sharing.

- Repository: https://github.com/ZimengXiong/ExcaliDash
- Website: https://excalidash.xyz
- Stars: 1,597 · Forks: 158
- Language: TypeScript
- License: LGPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/zimengxiong-excalidash

## What ExcaliDash adds on top of Excalidraw

Excalidraw is an editor. It renders a scene and gives you a file. What it does not give you is a place to keep hundreds of those files, a way to sort them into collections, or a link you can hand to someone outside your team with a defined scope. ExcaliDash is that layer. The README describes it as a self-hosted dashboard and organizer for Excalidraw with live collaboration features, and the feature list is essentially the list of things the editor leaves to you: persistent storage, real time collaboration, version history and restore, search, drag and drop into collections, and scoped internal and external sharing.

The intended user is a small team or an individual who already runs Docker Compose and does not want drawings sitting in a vendor account. Multi-user authentication and OIDC are marked optional in the README, which means the same deployment can run as a single-user instance or as a shared one with sign-in. That optionality is the interesting design choice here: auth is a mode, not a prerequisite, and the compose file exposes it as AUTH_MODE with a default of local.

If you only ever draw one diagram and export a PNG, this project is heavier than the problem. The value shows up when drawings accumulate and you need to find, restore, or share them.

## How the pieces fit: backend, SQLite volume and WebSocket collaboration

The repository layout separates frontend and backend, with a Prisma schema in the backend and a Makefile at the root. The compose file shows the deployment shape: a backend service built from ./backend/Dockerfile, running with DATABASE_PROVIDER=sqlite and DATABASE_URL=file:/app/prisma/dev.db, listening on PORT=8000, with a named volume backend-data mounted at /app/prisma. That volume is where the database and the auto-generated secrets live, which is why the upgrade notes warn against adding -v to docker compose down.

Live collaboration is a WebSocket concern, and the project's topics list websocket explicitly. The compose file also sets init: true with a comment explaining that it runs an init process as PID 1 so that SIGTERM and SIGINT reach node and graceful shutdown (the comment names io.close and prisma.$disconnect) actually runs. That is a small detail with real consequences: without it, a container stop can skip the disconnect path.

The frontend is served alongside the backend and is reached at localhost:6767 in both quickstart paths. Requests that pass through a reverse proxy are governed by TRUST_PROXY, which the compose files set to false by default. The README is direct about this: only set TRUST_PROXY to a positive hop count such as 1 when requests always pass through a trusted reverse proxy that correctly sets forwarded headers. Getting that wrong is a security question, not a performance one.

## Installing ExcaliDash with Docker Compose

The recommended path is Docker Hub with Docker Compose v2. Three commands download the production compose file, pull the images, and start the containers. The README says the frontend is then available at localhost:6767.

```bash
curl -OL https://raw.githubusercontent.com/ZimengXiong/ExcaliDash/main/docker-compose.prod.yml
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
```

If you would rather build from source, the README gives a clone plus build path. The repository recommends the SSH clone, with an HTTPS alternative commented in the same block.

```bash
git clone git@github.com:ZimengXiong/ExcaliDash.git
docker compose build
docker compose up -d
```

Secrets are the first thing to decide. For a single-container deployment the README states that JWT_SECRET can be omitted and will be auto-generated and persisted in the backend volume on first start, but it recommends setting a fixed value explicitly for portability and most production deployments. The compose file also reads CSRF_SECRET from the environment. Neither has a documented default value in the README, so treat both as values you supply.

Upgrades follow the same shape. Pull the new images and recreate the containers, or stop, pull, and start if you prefer a clean cycle with more downtime.

```bash
docker compose -f docker-compose.prod.yml pull && \
  docker compose -f docker-compose.prod.yml up -d
```

The README adds two warnings to that sequence: do not add -v to down unless you intend to delete the persistent backend volume (the SQLite database and secrets), and only add --remove-orphans if you previously ran a different Compose file under the same project name. For anything past this point (reverse proxy, auth and OIDC, database provider, offline operation, backup, password policy), the root README defers to docs/DEPLOYMENT.md, and the environment-variable reference lives in docs/CONFIGURATION.md.

## Where ExcaliDash is the wrong tool

The README labels the deployment BETA in a caution block and repeats that production-readiness depends on deployment controls: TLS, a trusted reverse proxy, fixed secrets, backups, and endpoint rate limits. A second caution block says the project is in BETA and asks you to back up your data regularly. Take both literally. This is not a project that claims to be finished, and the recent release list is dominated by dev-tagged builds (0.6.2-dev and 0.6.1-dev) alongside 0.6.0.

There are concrete cases where it does not fit. If you need a desktop whiteboard with no server, the installation section is irrelevant to you and a local Excalidraw app is the smaller answer. If you cannot put a reverse proxy in front of the service, you are left deciding whether to expose the backend directly, and the README's own caution list assumes you did not. If your organization forbids outbound calls from deployed services, note that the in-app update notifier checks GitHub Releases and must be disabled on the backend with UPDATE_CHECK_OUTBOUND=false.

There is also a migration dimension. The README shows a migration screen for moving from v0.3 and an admin bootstrap flow, which implies that upgrading across that boundary is a deliberate operation rather than a pull-and-restart. Older deployments should read the release notes for the specific version before assuming the generic upgrade commands are sufficient. The README does not document rollback, so a failed upgrade has no described reverse path beyond restoring your own backup.

## ExcaliDash compared with running Excalidraw alone

The honest alternative is plain Excalidraw: use the editor, export .excalidraw files, and keep them wherever you already keep files. The difference in approach is not the canvas, which is the same, but where state lives and who can reach it. Plain Excalidraw has no server-side collection model, no share scopes, and no restore history. You get files and whatever your file host provides.

ExcaliDash moves that responsibility into a backend with a SQLite database on a named volume, and adds the features that only make sense once there is a server: version history with restore, scoped internal and external sharing, search, and collections. The cost is operational. You now own a container, a volume, secret management, a reverse proxy decision, and an upgrade path that the README explicitly warns can destroy data if you pass -v to down.

One point in ExcaliDash's favour for people who care about lock-in: the README states that export and import use a non-proprietary archival format that stores drawings in plain .excalidraw format. That means the dashboard is a management layer over files you could still read elsewhere, rather than a new document format you would have to reverse. If your reason for self-hosting is data ownership, that detail matters more than any single feature.

## Maintenance, licensing and the cost of staying current

The last push to the repository was on 2026-09-10, and the most recent release is v0.6.2-dev.fcc3c39 from 2026-08-23. The project is not archived. The version string is read from a VERSION file by the Makefile, and releases carry a changelog target, so version bumps and release notes are part of the normal workflow rather than afterthoughts.

Upgrade cost is mostly your own: pull, recreate, and confirm the volume survived. The README gives the commands and the two flags to avoid. It does not describe a rollback procedure, so the practical rollback is the export/import archive plus your own database backup. Budget for that rather than assuming a failed upgrade is reversible by pulling an older tag.

Licensing is LGPL-3.0. The practical implication for most readers is that you can self-host it, and that if you modify the licensed code and distribute the result, the LGPL's terms attach to that distribution. Running it internally is a different situation from shipping a modified fork to customers. This is a description of the licence identifier, not legal advice; if you plan to redistribute a modified build, read the licence text in the repository's LICENSE file and get proper advice.

The operational surface is small but not zero: a backend container, a frontend, one volume, and environment variables documented in docs/CONFIGURATION.md. The repository also carries a lab compose file and a configuration lab doc for validating release candidates across local configurations, which is the maintainers' answer to testing combinations you might otherwise discover in production.

## Conclusion

Adopt ExcaliDash if you already run Docker Compose and want Excalidraw drawings to live on your own volume with collections, version restore, and internal or external share scopes. Do not adopt it if you need a single-user desktop whiteboard, if you cannot terminate TLS in front of it, or if you expect a stable release: the README labels the deployment BETA and repeats the advice to back up data regularly. Before putting real drawings in it, verify three things yourself: that your reverse proxy sets forwarded headers before you change TRUST_PROXY from false, that JWT_SECRET and CSRF_SECRET are fixed values rather than auto-generated ones, and that a restore from the export/import archive actually reproduces a drawing. The in-app update notifier calls GitHub Releases unless you set UPDATE_CHECK_OUTBOUND=false, so confirm that behaviour against your outbound network policy.

## FAQ

### What is ExcaliDash?

It is a self-hosted dashboard and organizer for Excalidraw with live collaboration features. The README lists persistent storage, real time collaboration, version history and restore, optional multi-user authentication with OIDC, scoped internal and external sharing, search, collections, and export/import for backup.

### How do I install ExcaliDash?

The recommended path is Docker Hub with Docker Compose v2: download docker-compose.prod.yml, run docker compose -f docker-compose.prod.yml pull, then docker compose -f docker-compose.prod.yml up -d. The frontend is then reachable at localhost:6767 according to the README.

### Is ExcaliDash production-ready?

The README labels the deployment BETA and says production-readiness depends on deployment controls such as TLS, a trusted reverse proxy, fixed secrets, backups, and endpoint rate limits. It also asks users to back up data regularly.

### Why does ExcaliDash report an origin not allowed error?

The compose files set TRUST_PROXY=false by default, and the README says to set it to a positive hop count such as 1 only when requests always pass through a trusted reverse proxy that correctly sets forwarded headers. Misconfigured proxy headers are the documented area to check, and the full environment-variable reference is in docs/CONFIGURATION.md.

## Sources

- [License: LGPL-3.0](https://github.com/ZimengXiong/ExcaliDash/blob/main/LICENSE)
- [Project website](https://excalidash.xyz)
- [README](https://github.com/ZimengXiong/ExcaliDash/blob/main/README.md)
- [Releases](https://github.com/ZimengXiong/ExcaliDash/releases)
- [ZimengXiong/ExcaliDash on GitHub](https://github.com/ZimengXiong/ExcaliDash)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zimengxiong-excalidash
