How to Deploy a Kaneo Application: 5 Methods for Production and Development

You can deploy Kaneo using drim CLI for automated setup, Docker Compose for local testing, or Helm charts for Kubernetes clusters, with optional external PostgreSQL and Kubernetes Secrets for production security.

Kaneo is an open-source project management platform built with Hono, Drizzle ORM, and Better Auth on the backend, paired with a React frontend. The entire application ships as a single container image from ghcr.io/usekaneo/kaneo:latest, bundling both API and web layers. This unified architecture simplifies deployment across environments, whether you're running a local instance or scaling across a production Kubernetes cluster.

Quick-Start One-Click Deployment with drim

The fastest path to a production-ready Kaneo instance uses the drim CLI, which automates container pulls, HTTPS certificate provisioning, and database initialization.

According to the Kaneo README, run:

curl -fsSL https://assets.kaneo.app/install.sh | sh
drim setup

This method handles SSL termination, reverse proxy configuration, and database creation without manual intervention. It's the recommended approach for teams without existing container orchestration infrastructure.

Docker Compose Deployment for Local Testing

For development environments or small self-hosted deployments, a minimal compose.yml spins up PostgreSQL alongside the Kaneo container. The configuration in [compose.yml](https://github.com/usekaneo/kaneo/blob/main/compose.yml) demonstrates the expected service structure.

First, copy the environment template:

cp .env.sample .env

Edit .env to set POSTGRES_PASSWORD and AUTH_SECRET (minimum 32 characters). Then deploy:

services:
  postgres:
    image: postgres:16-alpine
    env_file: .env
    ports: ["5432:5432"]
    volumes: ["postgres_data:/var/lib/postgresql/data"]
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U kaneo -d kaneo"]
      interval: 10s
      timeout: 5s
      retries: 5

  kaneo:
    image: ghcr.io/usekaneo/kaneo:latest
    ports: ["5173:5173"]
    env_file: .env
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

volumes:
  postgres_data:

Start with:

docker compose up -d

Access the application at http://localhost:5173. The healthcheck ensures PostgreSQL is ready before Kaneo attempts connections, preventing startup race conditions.

Kubernetes Deployment with Helm Charts

For production clusters, the official Helm chart under charts/kaneo/ provisions Kaneo with configurable ingress, TLS, and resource limits as documented in [charts/kaneo/README.md](https://github.com/usekaneo/kaneo/blob/main/charts/kaneo/README.md).

Basic Installation

Create a namespace and install:

helm install kaneo oci://ghcr.io/usekaneo/charts/kaneo \
  --namespace kaneo --create-namespace
kubectl port-forward svc/kaneo-kaneo 5173:5173 -n kaneo

Production with Ingress

Expose via HTTPS using your cluster's ingress controller:

helm install kaneo oci://ghcr.io/usekaneo/charts/kaneo \
  --namespace kaneo --create-namespace \
  --set ingress.enabled=true \
  --set ingress.className=nginx \
  --set "ingress.hosts[0].host=mydomain.com"

All parameters are defined in [charts/kaneo/values.yaml](https://github.com/usekaneo/kaneo/blob/main/charts/kaneo/values.yaml). Environment-specific configuration lives under kaneo.env, including authSecret and clientUrl values.

External PostgreSQL Configuration

For scalable production deployments, disable the bundled PostgreSQL and connect to a managed database. Set postgresql.enabled=false and provide connection details via kaneo.env.database.external as shown in the Helm documentation:

kaneo:
  env:
    authSecret: "secure-32-char-secret"
    clientUrl: "https://kaneo.your-domain.com"
    database:
      external:
        enabled: true
        host: "db.example.com"
        port: 5432
        database: "kaneo"
        username: "kaneo_user"
        password: "strong-password"

This separation allows independent scaling, automated backups, and high-availability configurations managed by your database provider.

Secrets Management with Kubernetes

Production deployments should store sensitive values in Kubernetes Secrets rather than plain values.yaml files. Create a secret with your authentication and database credentials:

kubectl create secret generic kaneo-secrets \
  --namespace kaneo \
  --from-literal=auth-secret="a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  --from-literal=postgres-password="my$ecureP%ssw0rd"

Reference it in your deployment configuration:

kaneo:
  env:
    existingSecret:
      enabled: true
      name: "kaneo-secrets"
      key: "auth-secret"

This pattern prevents credential leakage in version control and enables secret rotation without redeploying the application.

Required Environment Variables

Several variables are mandatory for correct operation, as defined in .env.sample:

Variable Purpose Requirement
AUTH_SECRET Encryption key for Better Auth sessions Minimum 32 characters
KANEO_CLIENT_URL Public-facing URL for CORS and redirects Must match browser address exactly
POSTGRES_PASSWORD / DATABASE_URL Database authentication Required unless using socket connections

Critical: If KANEO_CLIENT_URL mismatches the actual browser URL, authentication fails with an "invalid origin" error. The application generates a random AUTH_SECRET at startup only if the variable is absent—explicit configuration is strongly recommended for production stability.

Container Architecture Details

The multi-stage Dockerfile builds both backend and frontend into a single image. The API routes under /api/* are served by Hono, while the React application handles all other paths on port 5173. Optional Redis can be configured for WebSocket pub/sub in multi-replica deployments, though the default in-memory adapter suffices for single-instance setups.

Summary

  • drim CLI provides the fastest production deployment with automatic HTTPS and database setup
  • Docker Compose works best for local development and small teams, using the sample [compose.yml](https://github.com/usekaneo/kaneo/blob/main/compose.yml)
  • Helm charts enable scalable Kubernetes deployments with ingress, resource limits, and external database support
  • External PostgreSQL should replace bundled databases for production workloads requiring HA and backups
  • Kubernetes Secrets properly isolate sensitive configuration from application code

Frequently Asked Questions

What is the minimum server requirement for running Kaneo?

Kaneo runs comfortably on a single CPU core with 1GB RAM for small teams. The containerized architecture means resource limits are primarily dictated by PostgreSQL performance and concurrent user load. For production, allocate at least 2GB RAM and enable connection pooling for the database.

Why does login fail with "invalid origin" after deployment?

This error occurs when KANEO_CLIENT_URL (or kaneo.env.clientUrl in Helm) doesn't match the URL in your browser address bar. Better Auth validates the origin header for security. Check for trailing slashes, protocol mismatches (http vs https), or port differences—the value must be exact.

Can I split the API and frontend into separate containers?

The official image bundles both layers for operational simplicity. While the source structure separates apps/api and apps/web, you'd need custom build pipelines to containerize them independently. This is only recommended if you have specific caching or scaling requirements that justify the added complexity.

How do I migrate data when switching from bundled to external PostgreSQL?

Use pg_dump from the running container to export, then restore to your external database. Update connection settings, set postgresql.enabled=false, and redeploy. The Drizzle ORM schema in [apps/api/src/database/schema.ts](https://github.com/usekaneo/kaneo/blob/main/apps/api/src/database/schema.ts) ensures compatibility across deployment modes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →