Docker Setup
Docker Setup
Section titled “Docker Setup”Kazier’s backend is a single Go binary (Tesseract embedded for OCR) and
its database is PostgreSQL 17. The repository ships a docker-compose.yml
that runs the whole stack: the database and the backend API.
Services
Section titled “Services”| Service | Image | Purpose |
|---|---|---|
postgres | postgres:17-alpine | Metadata database |
backend | built from ./backend (Dockerfile) | Go API (image also published to Docker Hub) |
The published image is docker.io/thirdshop/kasier (tagged
vX.Y.Z + latest).
The paddleocr service seen in the historical file was rejected in favor of
Tesseract, which the backend calls directly as a system command.
Prerequisites
Section titled “Prerequisites”- Docker with Compose V2
- mandatory environment variables (see Environment Variables):
AUTH_SECRET,ADMIN_USERNAME,ADMIN_PASSWORD
docker-compose.yml
Section titled “docker-compose.yml”services: postgres: image: postgres:17-alpine ports: - "5432:5432" environment: POSTGRES_DB: ${POSTGRES_DB:-kazier_dev} POSTGRES_USER: ${POSTGRES_USER:-kazier} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-kazier} volumes: - postgres-data:/var/lib/postgresql/data restart: unless-stopped healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-kazier}"] interval: 10s timeout: 5s retries: 5
backend: build: context: ./backend dockerfile: Dockerfile args: VERSION: ${VERSION:-dev} ports: - "${PORT:-8080}:8080" environment: PORT: 8080 DATABASE_URL: postgres://${POSTGRES_USER:-kazier}:${POSTGRES_PASSWORD:-kazier}@postgres:5432/${POSTGRES_DB:-kazier_dev}?sslmode=disable UPLOAD_DIR: /app/uploads MAX_FILE_SIZE_MB: ${MAX_FILE_SIZE_MB:-50} OCR_LANG: ${OCR_LANG:-fra+eng} AUTH_SECRET: ${AUTH_SECRET:?AUTH_SECRET required} ADMIN_USERNAME: ${ADMIN_USERNAME:?ADMIN_USERNAME required} ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD required} volumes: - backend-uploads:/app/uploads depends_on: postgres: condition: service_healthy restart: unless-stopped
volumes: postgres-data: backend-uploads:Commands
Section titled “Commands”# Copy the example env and edit the secretscp backend/.env.example .env
# Start the whole stack (waits for the database healthcheck)docker compose up -d --build
# Health checkcurl http://localhost:8080/api/v1/health# → {"data":{"status":"healthy"}}
# Follow logsdocker compose logs -f
# Stop the stackdocker compose down
# Stop and delete the data volume (⚠️ destroys metadata)docker compose down -vRotate POSTGRES_PASSWORD, AUTH_SECRET and the admin credentials outside of
the compose file (e.g. your .env, Docker secrets). Never use the defaults in
production.
Container environment
Section titled “Container environment”| Variable | Default | Description |
|---|---|---|
POSTGRES_DB | kazier_dev | Database created at first boot |
POSTGRES_USER | kazier | Database user |
POSTGRES_PASSWORD | kazier | Password (change for production) |
VERSION | dev | Build arg injected into main.version (ldflags) |
Backend variables are documented in Environment Variables.
Backend image
Section titled “Backend image”The backend image is built by a multi-stage Dockerfile:
- Builder (
golang:1.26-alpine): compiles a static binary withCGO_ENABLED=0and the version baked in (ldflags). - Runtime (
alpine, non-root user): ships Tesseract with English and French language data (fra+eng, defaultOCR_LANG),ca-certificates, a persistentUPLOAD_DIRat/app/uploads, a DockerHEALTHCHECK, and OCI labels (AGPL-3.0-only, source URL, version).
The server listens on all interfaces (:PORT, default 8080) — no HOST
variable is needed.
To run the published image instead of building it locally:
docker run --rm \ -e AUTH_SECRET="$AUTH_SECRET" \ -e ADMIN_USERNAME="$ADMIN_USERNAME" \ -e ADMIN_PASSWORD="$ADMIN_PASSWORD" \ -e DATABASE_URL="postgres://kazier:kazier@host.docker.internal:5432/kazier_dev?sslmode=disable" \ -p 8080:8080 \ thirdshop/kasier:latest