Installation

Self-host Draftila on your own server with Docker in minutes.

Quick Start

The fastest way to get Draftila running. This uses SQLite and local file storage — no external dependencies needed.

1. Generate an auth secret:

openssl rand -base64 32

2. Start with a single command:

docker run -d \
  --name draftila \
  -p 3001:3001 \
  -e BETTER_AUTH_SECRET="your-generated-secret" \
  -e ADMIN_EMAIL="admin@example.com" \
  -e ADMIN_PASSWORD="your-admin-password" \
  -e STORAGE_DRIVER="local" \
  -e STORAGE_PATH="./storage" \
  -v draftila_data:/app/data \
  -v draftila_storage:/app/data/storage \
  --restart unless-stopped \
  draftila/draftila:latest

Open http://localhost:3001 to get started.

Docker Compose

For production, use Docker Compose for easier management and updates.

Create a docker-compose.yml:

services:
  draftila:
    image: draftila/draftila:latest
    ports:
      - '3001:3001'
    environment:
      BETTER_AUTH_SECRET: '${BETTER_AUTH_SECRET}'
      BETTER_AUTH_URL: 'https://draftila.example.com'
      FRONTEND_URL: 'https://draftila.example.com'
      ADMIN_EMAIL: 'admin@example.com'
      ADMIN_PASSWORD: '${ADMIN_PASSWORD}'
      STORAGE_DRIVER: 'local'
      STORAGE_PATH: './storage'
    volumes:
      - draftila_data:/app/data
      - draftila_storage:/app/data/storage
    restart: unless-stopped

volumes:
  draftila_data:
  draftila_storage:

Start it:

docker compose up -d

PostgreSQL

For teams or high-availability setups, use PostgreSQL instead of SQLite.

services:
  draftila:
    image: draftila/draftila:latest
    ports:
      - '3001:3001'
    environment:
      BETTER_AUTH_SECRET: '${BETTER_AUTH_SECRET}'
      BETTER_AUTH_URL: 'https://draftila.example.com'
      FRONTEND_URL: 'https://draftila.example.com'
      ADMIN_EMAIL: 'admin@example.com'
      ADMIN_PASSWORD: '${ADMIN_PASSWORD}'
      DB_DRIVER: 'postgres'
      DATABASE_URL: 'postgres://draftila:password@db:5432/draftila'
      STORAGE_DRIVER: 'local'
      STORAGE_PATH: './storage'
    volumes:
      - draftila_storage:/app/data/storage
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: draftila
      POSTGRES_PASSWORD: password
      POSTGRES_DB: draftila
    volumes:
      - draftila_db:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U draftila']
      interval: 5s
      timeout: 5s
      retries: 5
    restart: unless-stopped

volumes:
  draftila_storage:
  draftila_db:

Environment Variables

All available configuration options.

VariableDefaultDescription
BETTER_AUTH_SECRETrequiredA random secret used for signing auth tokens. Generate with: openssl rand -base64 32
ADMIN_EMAILrequiredEmail address for the initial admin account created on first startup.
ADMIN_PASSWORDrequiredPassword for the initial admin account. Change this to a strong password.
BETTER_AUTH_URLhttp://localhost:3001The public URL of your Draftila instance. Used for auth callbacks.
FRONTEND_URLhttp://localhost:3001The public URL for the frontend. Usually the same as BETTER_AUTH_URL.
PORT3001The port the server listens on inside the container.
DB_DRIVERsqliteDatabase driver. Use "sqlite" for single-server or "postgres" for production.
DATABASE_URLfile:/app/data/draftila.sqliteDatabase connection string. For PostgreSQL: postgres://user:pass@host:5432/draftila
STORAGE_DRIVERlocalFile storage driver. "local" stores files on disk.
STORAGE_PATH/app/data/storagePath for local file storage inside the container.
TRUSTED_PROXY_IPSComma-separated list of trusted reverse proxy IPs for X-Forwarded-For.
SKIP_DB_MIGRATE0Set to "1" to skip automatic database migrations on startup.

Reverse Proxy

When running behind a reverse proxy (Nginx, Caddy, Traefik), make sure to:

  • Set BETTER_AUTH_URL and FRONTEND_URL to your public domain
  • Forward WebSocket connections (needed for real-time collaboration)
  • Add your proxy IP to TRUSTED_PROXY_IPS

Caddy example:

draftila.example.com {
  reverse_proxy localhost:3001
}

Updating

Pull the latest image and restart:

docker compose pull
docker compose up -d

Database migrations run automatically on startup. Set SKIP_DB_MIGRATE=1 to disable.