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:
- Installs
pnpmin anode:20-alpinebase - Copies workspace manifests for dependency caching
- Installs dependencies with
pnpm install - Builds the
emailandpermissionspackages - Compiles the API from
apps/apitodist/
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:
- Installs dependencies
- Builds
apps/webtodist/
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
appuseraccount 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 -dwith the pre-built image from GitHub Container Registry - For development: Use
docker compose -f compose.local.yml up -d --buildto compile from source - The
Dockerfile.kaneoimplements a three-stage build (api-builder, web-builder, runtime) for optimized, secure containers - Minimum required configuration:
POSTGRES_PASSWORDandAUTH_SECRETin.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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →