4.5 KiB
Deployment
Local development
Backend
cd backend
go mod download
go run ./cmd/kereru-forms \
--listen-addr 127.0.0.1 \
--port 8080 \
--log-format console \
--db-dsn "file:./kereru-dev.db?_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)"
Useful flags:
kereru-forms --help
Frontend
cd frontend
npm install
npm run dev
Vite serves on http://localhost:5173 and proxies /api/* to http://localhost:8080. To point at another API host, set VITE_API_BASE_URL at build/dev time:
VITE_API_BASE_URL=http://localhost:8080 npm run dev
Production build without containers
# Backend binary
cd backend
CGO_ENABLED=0 go build -ldflags "-s -w -X main.version=1.0.0" -o kereru-forms ./cmd/kereru-forms
# Frontend assets
cd ../frontend
npm ci
npm run build
Run the binary with the SPA directory and a persistent database:
KERERU_STATIC_DIR=../frontend/dist \
KERERU_DB_DSN="file:/var/lib/kereru/kereru.db?_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)" \
KERERU_LOG_FORMAT=json \
KERERU_ENVIRONMENT=production \
./kereru-forms --listen-addr 0.0.0.0 --port 8080
The binary serves the API at /health, /forms, /submissions and the SPA for every other path.
Docker
Build from the repository root so both backend/ and frontend/ are in context:
docker build -f docker/Dockerfile -t kereru-forms:1.0.0 .
docker run -d --name kereru-forms \
-p 8080:8080 \
-v kereru-data:/data \
-e KERERU_CORS_ORIGINS="https://forms.example.com" \
kereru-forms:1.0.0
Or with Compose:
docker compose -f docker/docker-compose.yml up -d --build
The image runs as an unprivileged user, stores SQLite data in /data, and serves the built frontend from /app/static.
Podman
The image is OCI-compatible. Use rootless Podman:
podman build -f docker/Dockerfile -t kereru-forms:1.0.0 .
podman run -d --name kereru-forms \
-p 8080:8080 \
-v kereru-data:/data:Z \
-e KERERU_CORS_ORIGINS="*" \
kereru-forms:1.0.0
With Compose (either podman-compose or docker compose using the Podman socket):
podman-compose -f docker/docker-compose.yml up -d --build
podman generate systemd --new --name kereru-forms (or a Quadlet unit) can turn the container into a system service.
Kubernetes
-
Build, tag and push the image to a registry reachable by the cluster:
docker build -f docker/Dockerfile -t registry.example.com/kereru-forms:1.0.0 . docker push registry.example.com/kereru-forms:1.0.0 -
Update
image:and the Ingress host indeploy/k8s.yaml. -
Apply:
kubectl apply -f deploy/k8s.yaml kubectl -n kereru-forms rollout status deployment/kereru-forms
The manifest includes a namespace, config map, 1 GiB ReadWriteOnce PVC mounted at /data, a Recreate deployment (SQLite is single-writer), liveness/readiness probes on /health, a service on port 80 and an Ingress. A writable /tmp emptyDir is mounted because the container root filesystem is read-only.
Scaling notes
SQLite requires a single writer. Keep replicas: 1 and use the Recreate strategy. To scale horizontally, implement a network database adapter (PostgreSQL/MariaDB) behind database.Store, then switch dbDriver/dbDsn and lift the Deployment restrictions.
Use a ReadWriteMany volume only if you replace SQLite; do not share a SQLite file across pods.
Configuration in production
Prefer environment variables (twelve-factor) or a mounted YAML/JSON file:
kereru-forms --conf /etc/kereru/config.yaml
Typical production settings:
KERERU_LOG_FORMAT=jsonKERERU_ENVIRONMENT=productionKERERU_CORS_ORIGINS=https://forms.example.comKERERU_TELEMETRY_ENABLED=trueandOTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318KERERU_STATIC_DIR=/app/static- SQLite DSN on a persistent volume:
file:/data/kereru.db?_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)
Backups
For SQLite, back up the database file while the service is stopped, or use the SQLite online backup API/.backup command. Keep the volume and file permissions owned by the runtime user (UID used in the container image).
Security
- Terminate TLS at the ingress/load balancer.
- Management routes (
/forms,/submissions,/forms/{id}/pdf) are not authenticated; restrict them with an auth proxy or network policy. - Set
KERERU_CORS_ORIGINSto the exact frontend origin in production. - Do not expose the SQLite file over a network share.