A self-hostable app with server-side persistence and multiple boards based on Excalidraw.
docker run -p 80:80 -p 4000:4000 ghcr.io/ozencb/excalidraw-persist:latest
- 💾 Server-side persistence of drawings, images, library objects
- 📑 Multiple boards/tabs support
- 🗑️ Trash functionality for deleted boards
- 🗃️ SQLite database for simple deployment
- Collaboration support
This project uses pnpm workspaces as a monorepo. Make sure to create a .env file with necessary values. You can take a look at packages/server/.env.example as a starting point.
# Clone the repository
git clone https://github.com/ozencb/excalidraw-persist.git
cd excalidraw-persist
# Install dependencies
pnpm install
# Create environment configuration
cp packages/server/.env.example packages/server/.env
# Start development servers (client and server)
pnpm dev
# Build for production
pnpm buildThe easiest way to deploy Excalidraw Persist is using Docker and Docker Compose.
- Clone the repository:
git clone https://github.com/ozencb/excalidraw-persist.git cd excalidraw-persist - Start the containers:
docker-compose up -d
- Access the application at
http://localhost(or your server's IP/domain)
or run
docker run -p 80:80 -p 4000:4000 ghcr.io/ozencb/excalidraw-persist:latest- Access the application at
http://localhost(or your server's IP/domain)
There are some convenience scripts included in the root package.json:
pnpm docker:build- Build the Docker imagespnpm docker:up- Start the containers in detached modepnpm docker:down- Stop and remove the containerspnpm docker:logs- View the container logs in follow mode
The Docker setup uses the following default configuration:
- Client accessible on port 80
- Server API running on port 4001 (mapped to internal port 4000)
- Data persisted in a local
./datavolume
The server container accepts the following environment variables:
PORT- The port the server will listen on (default: 4000)NODE_ENV- The environment mode (default: production)DB_PATH- The path to the SQLite database file (default: /app/data/database.sqlite)
You can modify these in the docker-compose.yml file:
# Example custom configuration
server:
environment:
- PORT=4000
- NODE_ENV=production
- DB_PATH=/app/data/custom-database.sqlite- Node.js (v22 or newer)
- pnpm (v10 or newer)
- Clone and prepare the application:
git clone https://github.com/ozencb/excalidraw-persist.git cd excalidraw-persist pnpm install cp packages/server/.env.example packages/server/.env # Configure your .env file pnpm build
- Start the server:
pnpm start
- For production, consider using a process manager like PM2:
npm install -g pm2 pm2 start pnpm --name "excalidraw-persist" -- start pm2 save - Set up a reverse proxy with Nginx or Apache for proper SSL termination
If you encounter issues:
- Check the application logs:
- Docker:
docker-compose logsorpnpm docker:logs - Manual: Check the console output where the app is running
- Docker:
- Verify network connectivity:
- Ensure ports are properly exposed and not blocked by firewalls
- Verify the server is accessible from the client
- Database issues:
- Check that the SQLite database file is being created
- Ensure the application has write permissions to the database directory
The application stores all data in an SQLite database file. To backup your data:
-
Docker deployment: Copy the data from the volume:
cp -r ./data/database.sqlite /your/backup/location/
-
Manual deployment: Copy the SQLite database file from your configured location
MIT