How to Use Kaneo with Docker: Complete Setup Guide

TLDR: Kaneo runs as a multi-stage Docker container with separate build stages for the API and web frontend, orchestrated via Docker Compose with PostgreSQL. Use compose.yml for production or compose.local.yml to build from source.

Kaneo is an open-source project management platform with first-class Docker support. This guide walks through exactly how to deploy Kaneo using Docker, whether you need a quick production setup or a local development environment. The repository provides production-ready Docker Compose configurations and a secure, slim runtime image.

Quick Start with Pre-Built Docker Image

The fastest way to run Kaneo uses the official image from GitHub Container Registry. This approach requires no local build and pulls a tested, production-ready container.

Configure Environment Variables

Kaneo requires several environment variables defined in .env.sample. Copy this file and customize:

cp .env.sample .env

Edit .env to set at minimum:

POSTGRES_PASSWORD=your_secure_password
AUTH_SECRET=$(openssl rand -hex 32)

The AUTH_SECRET is used for session encryption and must be 32+ characters.

Launch with Docker Compose

Run the pre-built stack:

docker compose -f compose.yml up -d

This starts two services:

  • PostgreSQL container with persistent volume
  • Kaneo application container on port 5173

Verify the API health endpoint:

curl http://localhost:5173/api/health

# Expected: {"status":"ok"}

Access the web UI at http://localhost:5173.

Building Kaneo from Source with Docker

For development or customization, use compose.local.yml to build containers directly from the repository source.

Local Build Workflow


# 1. Prepare environment

cp .env.sample .env

# Edit with your credentials

# 2. Build and start all services

docker compose -f compose.local.yml up -d --build

The --build flag forces fresh image construction. Subsequent runs can omit it unless dependencies change.

How the Local Build Works

The compose.local.yml orchestrates three services:

  • postgres — standard PostgreSQL container
  • api — built from apps/api/Dockerfile
  • web — built from apps/web/Dockerfile

Each service connects through Docker's internal network, with the web container proxying API requests as configured.

Understanding Kaneo's Multi-Stage Dockerfile

The production image uses Dockerfile.kaneo with three optimized stages that minimize final image size and attack surface.

Stage 1: API Builder


# FROM Dockerfile.kaneo

# api-builder stage

This stage:

  1. Installs pnpm in a node:20-alpine base
  2. Copies workspace manifests for dependency caching
  3. Installs dependencies with pnpm install
  4. Builds the email and permissions packages
  5. Compiles the API from apps/api to dist/

Dependency files are copied separately from source code, enabling Docker layer caching. Rebuilds only re-install dependencies when package.json changes.

Stage 2: Web Builder

Identical pattern for the frontend:

  1. Installs dependencies
  2. Builds apps/web to dist/

Each builder stage operates independently, allowing parallel execution.

Stage 3: Runtime

The final stage creates a minimal, secure production container:


# FROM Dockerfile.kaneo

# runtime stage

Key security and optimization features:

Feature Implementation
Base image node:20-alpine (minimal attack surface)
Web server nginx for static asset delivery
User privilege Unprivileged appuser (non-root)
Dependencies pnpm install --prod only (no dev dependencies)
Health check Built-in container health verification

The runtime copies only compiled artifacts from builder stages—no source code, build tools, or development dependencies remain in the final image.

Entrypoint Script

The container launches via kaneo-entrypoint.sh, which:

  • Injects runtime environment variables into nginx configuration
  • Starts the API server and nginx

This pattern allows the same image to run across environments with different configurations.

Docker Compose Configuration Reference

Production: compose.yml


# From compose.yml

services:
  postgres:
    image: postgres:16-alpine
    # Persistent volume for data

    
  kaneo:
    image: ghcr.io/usekaneo/kaneo:latest
    ports:
      - "5173:5173"
    environment:
      # Injected from .env

    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5173/api/health"]

The health check automatically restarts unhealthy containers.

Development: compose.local.yml


# From compose.local.yml

services:
  api:
    build:
      context: .
      dockerfile: apps/api/Dockerfile
    
  web:
    build:
      context: .
      dockerfile: apps/web/Dockerfile

Local builds use distinct Dockerfiles for each service, enabling independent iteration on API versus frontend.

Environment Variables and Configuration

The .env.sample file documents all supported variables:

Variable Required Purpose
POSTGRES_PASSWORD Yes Database authentication
POSTGRES_USER No Default: postgres
POSTGRES_DB No Default: kaneo
AUTH_SECRET Yes Session encryption key
DATABASE_URL Auto-generated Override connection string
REDIS_URL No Optional external Redis

Database URL format when overriding manually:


postgresql://user:password@host:port/database

Security Best Practices

Kaneo's Docker implementation follows container security fundamentals:

  • Non-root execution: The appuser account runs all processes
  • Minimal runtime: No build tools, compilers, or source code in production
  • Health verification: Automated restart on service failure
  • Layer caching: Dependency installation separated from source changes

The multi-stage build ensures the runtime image contains only what's necessary to execute—approximately the node:20-alpine base plus nginx, compiled JavaScript, and production npm packages.

Troubleshooting Docker Deployments

Container fails to start

Check logs for missing environment variables:

docker compose logs kaneo

Common causes: undefined AUTH_SECRET or invalid database credentials.

Database connection errors

Verify PostgreSQL container health:

docker compose ps

# Status should show "healthy"

Test connectivity from the Kaneo container:

docker compose exec kaneo wget -qO- http://localhost:5173/api/health

Build cache issues

Force clean rebuild:

docker compose -f compose.local.yml build --no-cache

Summary

  • For production: Use docker compose -f compose.yml up -d with the pre-built image from GitHub Container Registry
  • For development: Use docker compose -f compose.local.yml up -d --build to compile from source
  • The Dockerfile.kaneo implements a three-stage build (api-builder, web-builder, runtime) for optimized, secure containers
  • Minimum required configuration: POSTGRES_PASSWORD and AUTH_SECRET in .env
  • Architecture: Builder stages compile on the build platform; runtime stage runs anywhere with node:20-alpine

Frequently Asked Questions

What ports does Kaneo expose?

Kaneo exposes port 5173 for both the web UI and API. The same port serves static frontend assets and proxies API requests—no separate ports required.

Can I use an external PostgreSQL database?

Yes. Set DATABASE_URL in your .env file with your external connection string, and remove or disable the postgres service in your compose file.

How do I update to a new Kaneo version?

For pre-built images: docker compose -f compose.yml pull && docker compose -f compose.yml up -d. For local builds: git pull then docker compose -f compose.local.yml up -d --build.

Why does the runtime stage use nginx?

Nginx serves the compiled web frontend's static assets with optimal compression and caching headers. The API runs as a separate Node.js process, with nginx proxying requests to /api/* paths.

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 →