Skip to content

Deployment

raktim edited this page Aug 21, 2026 · 1 revision

Deployment

Two deployment paths are provided: plain Docker Compose (build from source, works anywhere Docker runs — a VPS, a home server, a NAS without CasaOS) and CasaOS (one-click install from pre-built images, once published to the App Store). Both are defined under deploy/.

Docker Compose

Files involved

  • deploy/docker-compose.yml — three services: postgres (16-alpine), backend (built from ../backend/Dockerfile), frontend (built from ../frontend/Dockerfile, nginx serving the SPA and reverse-proxying /api/*).
  • deploy/.env.example — template for the required secrets/ports.

Install

git clone https://github.com/Raktim94/KinetiRx.git
cd KinetiRx
cp deploy/.env.example deploy/.env

Edit deploy/.env and set, at minimum:

  • POSTGRES_PASSWORD — required, no default (Compose refuses to start without it).
  • JWT_SECRET — required; generate with openssl rand -hex 32. Changing this later invalidates every active session.
  • KINETIRX_ADMIN_PASSWORD — required on first boot only, to seed the EMP-ADMIN-1 "Master Admin" account. Once the employees table has a row, this variable is never read again — safe to remove from .env after first boot, but there is no self-service password reset, so store it somewhere durable before you do.
  • GEMINI_API_KEY — optional; leave blank to run AI OCR and the assistant in offline fallback mode.

Then bring the stack up:

docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d --build

Visit http://localhost:${HTTP_PORT:-3080}. The backend is also reachable directly at http://localhost:${BACKEND_PORT:-8080} for curl/health checks/admin scripts — the browser SPA itself never needs this, since nginx proxies /api/* internally (same-origin, no CORS involved in normal use).

Postgres is not published to the host by default — only reachable from the backend service over the internal Compose network — since it has no reason to be host- or internet-reachable in a normal deployment.

Health checks

All three services define container healthchecks:

  • postgres: pg_isready
  • backend: GET /api/health via wget --spider
  • (frontend has no explicit healthcheck in docker-compose.yml; it depends on backend being healthy before starting)

Check status with:

docker compose -f deploy/docker-compose.yml ps

Troubleshooting

  • Backend won't start / "JWT_SECRET is required": deploy/.env is missing or wasn't passed via --env-file. The Compose file uses Docker Compose's ${VAR:?error message} syntax for required vars — Compose refuses to render the config at all if they're unset, so this fails fast rather than starting with an empty secret.
  • Login fails after first boot / forgot the admin password: there's no reset flow. You'll need to update the bcrypt hash directly in Postgres, or wipe the employees table and restart the backend so it reseeds from KINETIRX_ADMIN_PASSWORD again (only reseeds when the table is empty).
  • Frontend loads but API calls fail: check docker compose logs backend for a crash, and confirm backend's healthcheck is passing (docker compose ps) — the frontend service waits on condition: service_healthy for backend, so if backend never becomes healthy, frontend requests will hit a proxy target that's still starting.
  • AI OCR / assistant returns "operating in offline mode": expected behavior when GEMINI_API_KEY is unset — not a bug. Set the key and restart the backend service to enable it.
  • Port already in use: change HTTP_PORT / BACKEND_PORT in deploy/.env (both default to 3080/8080).

Postgres data: volume, backup, restore

Data lives in the named volume kinetirx_postgres_data (declared in docker-compose.yml), not a bind mount — it persists across docker compose down (but not down -v, which deletes it).

Backup:

docker compose -f deploy/docker-compose.yml exec postgres \
  pg_dump -U kinetirx kinetirx > kinetirx-backup-$(date +%Y%m%d).sql

Restore (into a running, empty database):

cat kinetirx-backup-YYYYMMDD.sql | \
  docker compose -f deploy/docker-compose.yml exec -T postgres \
  psql -U kinetirx -d kinetirx

Raw volume backup/restore (whole-volume copy, useful for migrating hosts):

# Backup
docker run --rm -v kinetirx_postgres_data:/data -v "$PWD":/backup alpine \
  tar czf /backup/kinetirx-postgres-volume.tar.gz -C /data .

# Restore into a fresh volume
docker run --rm -v kinetirx_postgres_data:/data -v "$PWD":/backup alpine \
  tar xzf /backup/kinetirx-postgres-volume.tar.gz -C /data

Automate the pg_dump command on a cron/systemd timer for regular backups — nothing in this repo currently automates that for you.

Updating / upgrading

git pull
docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d --build

This rebuilds the backend and frontend images from the updated source and recreates only the containers that changed; postgres and its volume are untouched. Any new SQL files added under backend/migrations/ run automatically against the existing database on the new backend container's startup (migrations are additive/forward-only — there's no automatic rollback on upgrade).

Always take a pg_dump backup (above) before upgrading across a change that touches backend/migrations/.

CasaOS

deploy/casaos-manifest.yml is a separate x-casaos v2 compose-extension manifest, kept independent of docker-compose.yml because CasaOS installs apps by pulling published container images, not by building from a source checkout the way a VPS deployment does.

Current status: not yet submitted to the CasaOS App Store. The manifest references ghcr.io/raktim94/kinetirx-backend:latest and ghcr.io/raktim94/kinetirx-frontend:latest, which do not exist yet. Before submission:

docker build -t ghcr.io/raktim94/kinetirx-backend:latest -f backend/Dockerfile backend
docker build -t ghcr.io/raktim94/kinetirx-frontend:latest -f frontend/Dockerfile frontend
docker push ghcr.io/raktim94/kinetirx-backend:latest
docker push ghcr.io/raktim94/kinetirx-frontend:latest

Then submit deploy/casaos-manifest.yml per the CasaOS AppStore contribution process.

Once installed, the manifest auto-generates POSTGRES_PASSWORD, JWT_SECRET, and prompts for KINETIRX_ADMIN_PASSWORD and (optionally) GEMINI_API_KEY through the CasaOS install UI (see the x-casaos.envs descriptions in the manifest) — same first-boot behavior and same "no password reset" caveat as the Compose path above. Postgres data is stored under /DATA/AppData/$AppID/postgres on the host, which CasaOS's own backup/snapshot tooling can cover once installed.

Clone this wiki locally