SkillAgentSearch skills...

ExcaliDash

A self-hosted dashboard and organizer for Excalidraw with multi-user collaboration and scoped sharing.

Install / Use

/learn @ZimengXiong/ExcaliDash
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<img src="readme-assets/logoExcaliDash.png" alt="ExcaliDash Logo" width="80" height="88">

ExcaliDash

License PRs Welcome Docker

A self-hosted dashboard and organizer for Excalidraw with live collaboration features.

Table of Contents

Features

<details> <summary>Persistent storage for all your drawings</summary>

</details> <details> <summary>Real time collaboration</summary>

</details> <details> <summary>(Optional) Multi User Authentication, OIDC Support</summary>

Sign in with OIDC

Migration from v0.3

Admin Bootstrap

Admin Dashboard

</details> <details> <summary>Scoped internal & external sharing</summary>

</details> <details> <summary>Search your drawings</summary>

</details> <details> <summary>Drag and drop drawings into collections</summary>

</details> <details> <summary>Export/import your drawings for backup</summary>

Excalidash uses a non-proprietary archival format that stores your drawings in plain .excalidraw format

</details>

Upgrading

See release notes for a specific release.

ExcaliDash includes an in-app update notifier that checks GitHub Releases. If your deployment must not make outbound network calls, disable it on the backend:

UPDATE_CHECK_OUTBOUND=false

Docker Hub Upgrades

If you deployed using docker-compose.prod.yml (Docker Hub images), upgrade by pulling the latest images and recreating containers:

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

If you prefer a clean stop/start (more downtime, but simpler), you can do:

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

Notes:

  • Don’t add -v to down unless you intend to delete the persistent backend volume (your SQLite DB + secrets).
  • Only add --remove-orphans if you previously ran a different Compose file for the same project name and need to remove old/renamed services.

Installation

[!CAUTION] This is a BETA deployment and production-readiness depends on deployment controls: use TLS, trusted reverse proxy, fixed secrets, backups, and endpoint rate limits.

[!CAUTION] ExcaliDash is in BETA. Please backup your data regularly.

Quickstart

Prereqs: Docker + Docker Compose v2.

<details> <summary>Docker Hub (Recommended)</summary>

Docker Hub (Recommended)

# Download docker-compose.prod.yml
curl -OL https://raw.githubusercontent.com/ZimengXiong/ExcaliDash/main/docker-compose.prod.yml

# Pull images
docker compose -f docker-compose.prod.yml pull

# Run container
docker compose -f docker-compose.prod.yml up -d

# Access the frontend at localhost:6767

For single-container deployments, JWT_SECRET can be omitted and will be auto-generated and persisted in the backend volume on first start. For portability and most production deployments, set a fixed JWT_SECRET explicitly.

By default, the provided Compose files set TRUST_PROXY=false for safer setup. Only set TRUST_PROXY to a positive hop count (for example, 1) when requests always pass through a trusted reverse proxy that correctly sets forwarded headers.

</details> <details> <summary>Docker Build</summary>

Docker Build

# Clone the repository (recommended)
git clone git@github.com:ZimengXiong/ExcaliDash.git

# or, clone with HTTPS
# git clone https://github.com/ZimengXiong/ExcaliDash.git

docker compose build
docker compose up -d

# Access the frontend at localhost:6767
</details>

Advanced

<details> <summary>Reverse Proxy / Traefik</summary>

When running ExcaliDash behind Traefik, Nginx, or another reverse proxy, configure both containers so that API + WebSocket calls resolve correctly:

| Variable | Purpose | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | FRONTEND_URL | Backend allowed origin(s). Must match the public URL users access (for example https://excalidash.example.com). Supports comma-separated values for multiple addresses. | | TRUST_PROXY | Set to 1 when traffic passes through one trusted reverse-proxy hop (for example frontend nginx -> backend) and headers are sanitized. | | BACKEND_URL | Frontend container-to-backend target used by Nginx. Override when backend host differs from default service DNS/host. |

# docker-compose.yml example
backend:
  environment:
    # Single URL
    - FRONTEND_URL=https://excalidash.example.com
    # Trust exactly one reverse-proxy hop
    - TRUST_PROXY=1
    # Or multiple URLs (comma-separated) for local + network access
    # - FRONTEND_URL=http://localhost:6767,http://192.168.1.100:6767,http://nas.local:6767
frontend:
  environment:
    # For standard Docker Compose (default)
    # - BACKEND_URL=backend:8000
    # For Kubernetes, use the service DNS name:
    - BACKEND_URL=excalidash-backend.default.svc.cluster.local:8000
</details> <details> <summary>Scaling / HA (Current Limitations)</summary>

ExcaliDash currently supports running one backend instance.

Why:

| Area | Limitation | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Database | The backend uses a local SQLite file database by default (DATABASE_URL=file:/.../dev.db). Running multiple backend replicas either creates split-brain state (separate DB files/volumes) or requires sharing a single SQLite file across hosts, which is not a reliable deployment pattern. | | Collaboration | Real-time presence state is tracked in-memory in the backend process, so multiple replicas will fragment presence/collaboration unless a shared Socket.IO adapter is added. |

Recommended deployment pattern:

| Component | Guidance | | --------- | ----------------------------------------------------------------------- | | Backend | 1 replica, persistent volume, regular backups. | | Frontend | 1 replica is simplest; scaling is generally fine since it is stateless. |

</details> <details> <summary>Auth, Onboarding, and First Admin Setup</summary>

ExcaliDash supports local login and OIDC, and includes a one-time first-admin bootstrap key to protect initial setup/migration flows.

Auth modes:

| AUTH_MODE | Behavior | | ----------------- | -------------------------------------------------------------- | | local (default) | Native email/password login only. | | hybrid | Native login plus OIDC login. | | oidc_enforced | OIDC-only login (/auth/register and /auth/login disabled). |

If you upgrade and see an onboarding/setup flow, follow the UI. For emergency-only operator access, you can temporarily bypass the onboarding gate:

DISABLE_ONBOARDING_GATE=true docker compose -f docker-compose.prod.yml up -d

One-time first-admin bootstrap setup code (local auth only):

| What | Notes | | ---------------- | ------------------------------------------------------------------------------------ | | When required | Auth enabled and no active users (fresh install or certain migrations). | | Where to find it | Backend logs: [BOOTSTRAP SETUP] One-time admin setup code .... | | Behavior | Single-use; if you enter an invalid/expired code, check logs for the refreshed code. |

Find the current code in logs:

docker compose -f docker-compose.prod.yml logs backend --tail=200 | grep "BOOTSTRAP SETUP"

OIDC configuration (for hybrid / oidc_enforced) requires these backend env vars:

backend:
  environment:
    - AUTH_MODE=oidc_enforced
    - OIDC_PROVIDER_NAME=Authentik
    - OIDC_ISSUER_URL=https://auth.example.com/application/o/excalidash/
    - OIDC_CLIENT_ID=your-client-id
    # Optional for public clients; required for confidential clients
    # - 
View on GitHub
GitHub Stars896
CategoryDevelopment
Updated2h ago
Forks81

Languages

TypeScript

Security Score

100/100

Audited on Mar 28, 2026

No findings