Skip to content

Docker Deployment

Chris & Mike edited this page Mar 7, 2026 · 10 revisions

Docker Deployment

Run D1 Database Manager in Docker containers.

Overview

D1 Manager can be deployed using Docker for local development, testing, or self-hosted environments. The Docker setup provides an isolated, reproducible environment.

Important Notes:

  • Docker deployment is primarily for the frontend interface
  • The Cloudflare Worker backend still requires deployment to Cloudflare's edge network for production use with real D1 databases
  • You must set up the d1-manager-metadata database in Cloudflare D1 (see below)
  • R2 Backup/Restore and Scheduled Backups require the Worker + R2; Docker deployments can still use download/import for local backups

Use Cases

Docker is suitable for:

  • βœ… Local development and testing
  • βœ… Self-hosted frontend with Cloudflare Worker backend
  • βœ… Custom deployment environments
  • βœ… Isolated testing environments

Docker is NOT suitable for:

  • ❌ Complete standalone operation (requires Cloudflare Worker)
  • ❌ Replacing Cloudflare Worker deployment

Quick Start

Prerequisites

  • Docker installed (download)
  • Docker Compose (included with Docker Desktop)
  • Cloudflare Account with D1 access
  • Wrangler CLI for metadata database setup

Verify Installation:

docker --version    # Should show Docker version
docker compose version  # Should show compose version
wrangler --version  # Should show wrangler version

Metadata Database Setup

Before running the Docker container, you must create and initialize the metadata database in Cloudflare D1:

# 1. Login to Cloudflare
wrangler login

# 2. Create the metadata database
wrangler d1 create d1-manager-metadata

# 3. Clone the repository to get schema.sql
git clone https://github.com/neverinfamous/d1-manager.git
cd d1-manager

# 4. Initialize the schema
wrangler d1 execute d1-manager-metadata --remote --file=worker/schema.sql

Note for existing users upgrading: If you're upgrading from an earlier version, run the schema command again to add new tables (like undo_history for the rollback feature). Existing tables won't be affected:

# Safe to run on existing metadata database
wrangler d1 execute d1-manager-metadata --remote --file=worker/schema.sql

Verify:

wrangler d1 execute d1-manager-metadata --remote \
  --command="SELECT name FROM sqlite_master WHERE type='table';"

You should see: query_history, saved_queries, and undo_history

Pull Image from Docker Hub

docker pull writenotenow/d1-manager:latest

Run Container

docker run -d \
  --name d1-manager \
  -p 8080:80 \
  -e VITE_WORKER_API=https://your-worker.workers.dev \
  writenotenow/d1-manager:latest

Access: http://localhost:8080

Building from Source

Clone Repository

git clone https://github.com/neverinfamous/d1-manager.git
cd d1-manager

Build Docker Image

docker build -t d1-manager .

Dockerfile:

# Build stage
FROM node:24-alpine AS builder

WORKDIR /app

# Copy package files
COPY package*.json ./
RUN npm ci

# Copy source code
COPY . .

# Build application
RUN npm run build

# Production stage
FROM nginx:alpine

# Copy built files
COPY --from=builder /app/dist /usr/share/nginx/html

# Copy nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

Run Built Image

docker run -d \
  --name d1-manager \
  -p 8080:80 \
  d1-manager

Docker Compose

docker-compose.yml

services:
  d1-manager:
    image: writenotenow/d1-manager:latest
    container_name: d1-manager
    ports:
      - "8080:80"
    environment:
      - VITE_WORKER_API=https://your-worker.workers.dev
    restart: unless-stopped

Commands

Start:

docker compose up -d

Stop:

docker compose down

View Logs:

docker compose logs -f

Rebuild:

docker compose up -d --build

Environment Variables

Available Variables

VITE_WORKER_API:

  • Cloudflare Worker API endpoint
  • Required for production use
  • Format: https://your-worker.your-account.workers.dev
  • Or custom domain: https://api.yourdomain.com

Example:

docker run -d \
  -p 8080:80 \
  -e VITE_WORKER_API=https://d1-api.example.com \
  writenotenow/d1-manager:latest

Without Environment Variable

If VITE_WORKER_API is not set:

  • Uses window.location.origin
  • Expects worker at same domain
  • Suitable for proxied setups

Network Configuration

Port Mapping

Default:

-p 8080:80

Custom Port:

-p 3000:80  # Access on http://localhost:3000

HTTPS with Reverse Proxy:

# Use nginx or Caddy as reverse proxy
# See Reverse Proxy section below

Networking with Worker

Option 1: Cloud Worker (Recommended)

Docker Container (Frontend)
    ↓ HTTPS
Cloudflare Worker (Backend)
    ↓ HTTPS
Cloudflare D1 (Databases)

Option 2: Docker Network (Local Dev)

Docker Container (Frontend)
    ↓ HTTP
Docker Container (Worker Dev)
    ↓ Mock Data

Reverse Proxy Setup

nginx

nginx.conf:

server {
    listen 80;
    server_name d1.yourdomain.com;

    location / {
        proxy_pass http://localhost:8080;
        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;
    }
}

With HTTPS:

server {
    listen 443 ssl;
    server_name d1.yourdomain.com;

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

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Caddy

Caddyfile:

d1.yourdomain.com {
    reverse_proxy localhost:8080
}

Benefits:

  • Automatic HTTPS
  • Automatic certificate renewal
  • Simple configuration

Traefik

docker-compose.yml with Traefik:

services:
  traefik:
    image: traefik:v2.10
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro

  d1-manager:
    image: writenotenow/d1-manager:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.d1.rule=Host(`d1.yourdomain.com`)"
      - "traefik.http.routers.d1.entrypoints=websecure"
      - "traefik.http.routers.d1.tls=true"

Persistent Data

Note: Frontend is stateless (no data stored in container).

All data resides in:

  • Cloudflare D1 databases (via Worker)
  • Browser localStorage (theme preference)

No volumes needed for data persistence.

Production Deployment

Best Practices

1. Use Specific Version Tag:

docker pull writenotenow/d1-manager:<version>

2. Enable Health Checks:

services:
  d1-manager:
    image: writenotenow/d1-manager:<version>
    healthcheck:
      test:
        ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3

3. Set Resource Limits:

services:
  d1-manager:
    image: writenotenow/d1-manager:<version>
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 512M

4. Use Restart Policy:

services:
  d1-manager:
    restart: unless-stopped

5. Enable Logging:

services:
  d1-manager:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

Security

1. Run as Non-Root:

# In Dockerfile
USER nginx

2. Read-Only Filesystem:

services:
  d1-manager:
    read_only: true
    tmpfs:
      - /tmp
      - /var/cache/nginx

3. Drop Capabilities:

services:
  d1-manager:
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE

4. Use HTTPS:

  • Always use reverse proxy with HTTPS
  • Never expose directly to internet without TLS

Monitoring

Container Health

Check status:

docker ps
docker inspect d1-manager

View logs:

docker logs d1-manager
docker logs -f d1-manager  # Follow logs

Resource usage:

docker stats d1-manager

Application Health

HTTP Health Check:

curl http://localhost:8080/

Expected: HTML page loads successfully.

Updating

Pull Latest Image

docker pull writenotenow/d1-manager:latest
docker stop d1-manager
docker rm d1-manager
docker run -d \
  --name d1-manager \
  -p 8080:80 \
  -e VITE_WORKER_API=https://your-worker.workers.dev \
  writenotenow/d1-manager:latest

With Docker Compose

docker compose pull
docker compose up -d

Zero-Downtime Update

# Start new container with different name
docker run -d \
  --name d1-manager-new \
  -p 8081:80 \
  writenotenow/d1-manager:latest

# Test new container
curl http://localhost:8081/

# Switch traffic (update reverse proxy or port mapping)
# Stop old container
docker stop d1-manager
docker rm d1-manager

# Rename new container
docker rename d1-manager-new d1-manager

Troubleshooting

Container Won't Start

Check logs:

docker logs d1-manager

Common issues:

  • Port already in use
  • Invalid environment variables
  • Insufficient resources

Can't Access Application

Check container is running:

docker ps | grep d1-manager

Check port mapping:

docker port d1-manager

Test locally:

docker exec -it d1-manager wget -O- http://localhost

Worker API Connection Fails

Verify VITE_WORKER_API:

docker inspect d1-manager | grep VITE_WORKER_API

Test worker endpoint:

curl https://your-worker.workers.dev/api/databases

Check CORS settings in worker configuration.

High Memory Usage

Check stats:

docker stats d1-manager

Set memory limit:

docker run -d \
  --name d1-manager \
  -p 8080:80 \
  --memory="512m" \
  writenotenow/d1-manager:latest

Alternative: Kubernetes

Deployment YAML

apiVersion: apps/v1
kind: Deployment
metadata:
  name: d1-manager
spec:
  replicas: 3
  selector:
    matchLabels:
      app: d1-manager
  template:
    metadata:
      labels:
        app: d1-manager
    spec:
      containers:
        - name: d1-manager
          image: writenotenow/d1-manager:<version>
          ports:
            - containerPort: 80
          env:
            - name: VITE_WORKER_API
              value: "https://your-worker.workers.dev"
          resources:
            limits:
              cpu: "500m"
              memory: "512Mi"
            requests:
              cpu: "250m"
              memory: "256Mi"
---
apiVersion: v1
kind: Service
metadata:
  name: d1-manager
spec:
  selector:
    app: d1-manager
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer

Apply

kubectl apply -f deployment.yaml

Docker Hub

Official Image: writenotenow/d1-manager

Available Tags:

  • latest - Latest stable release
  • <version> - Specific version
  • dev - Development builds

Pull:

docker pull writenotenow/d1-manager:latest

Next Steps


Need Help? See Troubleshooting or open an issue.

Clone this wiki locally