Files
crumbs-original/docs/DEPLOYMENT.md
T
Claude effe7e3e72 fix(docker): make bind-mounted data folders writable on startup
The image switched to the node user (uid 1000) at build time, so a host
folder mounted at /data kept its host ownership and SQLite failed with
SQLITE_CANTOPEN in a restart loop. Named and anonymous volumes worked only
because Docker copies the image's /data ownership into them.

The container now starts as root, hands DATA_DIR and the database folder
to node (only entries not already owned by it), and execs the app via
setpriv as node. Containers started with an explicit `user:` skip this.

Adds a CI step that runs the image with a host-owned bind mount.

Fixes #93

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016MHECwBhBpM248EFSBi4L5
2026-10-06 08:43:59 +02:00

4.5 KiB

Deployment Guide

Quick Start

docker compose up -d

Open http://localhost:3000 and set your password.

Custom Configuration

# docker-compose.yml
services:
  crumbs:
    image: ghcr.io/bretzel-app/crumbs:latest
    ports:
      - "8080:3000"  # Change external port
    volumes:
      - /path/to/data:/data  # Custom data location
    environment:
      - ORIGIN=https://notes.example.com  # Your domain
    restart: unless-stopped

The app runs as the image's node user (uid 1000). On startup the container hands ownership of a bind-mounted data folder to uid 1000, so a folder created by any host user works as-is. If you set user: in compose, that step is skipped and the folder must already be writable by that user.

Reverse Proxy (nginx)

server {
    listen 443 ssl;
    server_name notes.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support (for future live sync)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Set ORIGIN=https://notes.example.com in your docker-compose.yml.

Backup

The SQLite database and attachments are stored in /data:

# Backup
docker compose exec crumbs tar czf - /data > crumbs-backup.tar.gz

# Or copy the volume directly
docker cp crumbs:/data ./backup

Update

docker compose pull
docker compose up -d

Manual Deployment (Node.js)

Prerequisites

  • Node.js 22+
  • pnpm

Steps

# Clone and install
git clone <repo-url> crumbs
cd crumbs
pnpm install

# Build
pnpm build

# Set environment
export DATABASE_URL=./data/crumbs.db
export ORIGIN=http://localhost:3000
export NODE_ENV=production

# Run
node build

Environment Variables

Core

Variable Default Description
DATABASE_URL ./data/crumbs.db SQLite database path
DATA_DIR ./data Directory for attachments
ORIGIN http://localhost:3000 Server origin (required for CSRF)
PORT 3000 HTTP port
NODE_ENV development Set to production for deployment

OAuth / SSO (optional)

Google, GitHub, and generic OIDC (Authentik, Keycloak, Okta, etc.) are supported. Providers are auto-enabled when their env vars are set. See AUTH.md for environment variables, callback URLs, provider-specific setup guides, and troubleshooting.

Email Notifications (optional)

Email notifications are auto-enabled when SMTP_HOST is set. See FEATURES.md for the full list of notification types.

Variable Default Description
SMTP_HOST — SMTP server hostname (e.g. smtp.example.com)
SMTP_PORT 587 SMTP port (587 for STARTTLS, 465 for SSL)
SMTP_USER — SMTP username (optional for unauthenticated relays)
SMTP_PASS — SMTP password
SMTP_FROM Crumbs <noreply@localhost> Sender address

Users can opt out of share notifications in Settings > Preferences.

Health Check

The Docker image includes a health check that pings /login:

docker inspect --format='{{.State.Health.Status}}' crumbs

MCP Server Configuration

Crumbs includes a built-in MCP (Model Context Protocol) server that allows AI assistants to interact with your notes. See ARCHITECTURE.md for technical details and the full tool list.

Setup

  1. Open Settings in the Crumbs UI
  2. Create an API key (give it a name like "Claude Code")
  3. Copy the key (shown only once)
  4. Configure your MCP client:
{
  "mcpServers": {
    "crumbs": {
      "type": "streamable-http",
      "url": "https://your-crumbs-instance/api/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_API_KEY"
      }
    }
  }
}

Security Notes

  • Always use HTTPS in production (via reverse proxy)
  • The ORIGIN variable must match your actual domain for CSRF protection
  • API keys are SHA-256 hashed (never stored in plain text)
  • See AUTH.md for authentication security details (password hashing, session expiry, PKCE)