Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
Deploying with Docker (self-hosted) #
Prefer to run KitBuild on your own server? The Docker image builds the app for a Bun runtime (no Cloudflare/Workers required) and serves it as a regular HTTP server:
- Database: local SQLite file (default) or a remote Turso database
- Uploads: material images are stored on a local disk volume instead of R2
- Static assets: served by the Bun server itself (no asset platform)
Files #
| File | Purpose |
|---|---|
Dockerfile |
Multi-stage image: pnpm install → vp build -c vite.docker.config.ts → run with Bun |
docker-compose.yml |
migrate (one-shot) + app services, shared data volume |
vite.docker.config.ts |
Build config: swaps cloudflare:workers for a filesystem shim (docker/shims/), forces the Node @libsql/client for file: URLs |
docker/server.ts |
Bun HTTP server: serves dist/client assets + delegates to the app handler |
docker/shims/cloudflare-workers.ts |
env.MATERIAL_IMAGES backed by MATERIAL_UPLOAD_DIR on disk |
Local quick start #
# 1. Configure environment (copy the example and adjust)
cp .env.example .env
# For a fully-local setup, set these in .env:
# DATABASE_MODE=local
# TURSO_DATABASE_URL=file:/app/data/kitbuild.sqlite
# (leave TURSO_AUTH_TOKEN empty)
# 2. Build and start (migrations run automatically, then the app)
vp run docker:up
# → open http://localhost:3000
# 3. Optional: seed demo data (admin@kitbuild.mail / admin123)
docker compose run --rm app bunx tsx scripts/seed/index.ts
# 4. Stop
vp run docker:down
BETTER_AUTH_SECRET is required — compose fails fast if it is missing from .env (use a random string of 32+ characters).
Production deployment #
On your VPS (requires Docker with the compose plugin):
# 1. Get the code
git clone <your-repo> kitbuild && cd kitbuild
# 2. Configure environment
cp .env.example .env
# Set (all values are interpolated into compose):
# BETTER_AUTH_SECRET=<random 32+ chars>
# VITE_APP_URL=https://maps.example.com ← public URL, baked into the client bundle at build time
# SITE_URL=https://maps.example.com
# BETTER_AUTH_URL=https://maps.example.com
# DATABASE_MODE=remote ← or keep 'local' for the SQLite volume
# TURSO_DATABASE_URL=libsql://your-db.turso.io
# TURSO_AUTH_TOKEN=your-turso-token
# 3. Build & start (first `up` also runs the migrate service)
docker compose up -d --build
# 4. Seed initial data (optional)
docker compose run --rm app bunx tsx scripts/seed/index.ts
Then put a reverse proxy in front (example with Caddy, handling TLS automatically):
maps.example.com {
reverse_proxy 127.0.0.1:3000
}
Persistence & upgrades #
- All persistent data lives in the
kitbuild-datavolume (/app/datainside the container): the SQLite file and uploaded images. Back it up (docker run --rm -v kitbuild-data:/data -v $PWD:/backup alpine tar czf /backup/kitbuild-data.tar.gz -C /data .). - To upgrade: pull the new code, then
docker compose up -d --build— the migrate service reapplies pending migrations before the new app starts. - Changing the public URL requires a rebuild (
VITE_APP_URLis inlined into the client bundle).
Docker environment reference #
| Variable | Default | Purpose |
|---|---|---|
DATABASE_MODE |
local |
local (SQLite volume) or remote (Turso) |
TURSO_DATABASE_URL |
file:/app/data/kitbuild.sqlite |
SQLite path (local) or libsql:// URL (remote) |
TURSO_AUTH_TOKEN |
(empty) | Turso token (required when DATABASE_MODE=remote) |
BETTER_AUTH_SECRET |
(required) | Session signing key, 32+ chars |
BETTER_AUTH_URL |
http://localhost:3000 |
Auth callback URL |
SITE_URL |
http://localhost:3000 |
Canonical site URL |
VITE_APP_URL (build) |
http://localhost:3000 |
Public URL baked into the client bundle |
VITE_SENTRY_DSN (build) |
(empty) | Sentry DSN (optional) |
PORT |
3000 |
Host port mapped to the container |
MATERIAL_UPLOAD_DIR |
/app/data/uploads |
Where uploaded material images are stored |
How the Docker build differs #
vite.docker.config.ts produces the same worker-shaped bundle as the Cloudflare build, but:
cloudflare:workersis aliased todocker/shims/cloudflare-workers.ts—env.MATERIAL_IMAGESreads/writesMATERIAL_UPLOAD_DIRinstead of R2.@libsql/clientis resolved to its/nodebuild and kept external, so localfile:SQLite URLs work through the native binding. (The worker build'sprocessshim is restored bydocker/server.ts, since the libsql binding needs the realprocess.arch.)docker/server.tsservesdist/clientassets itself and forwards everything else to the app handler.