Skip to main content

Self Host - Getting Started

This guide covers the standard self-hosted Kanera setup using Docker Compose.

Use it when you want to run Kanera on your own server with your own domains, database, uploads, backups, public API, and MCP endpoint.

Requirements

You need:

  • A server with Docker and Docker Compose.
  • A domain pointing at the server.
  • HTTPS in front of Kanera, usually through Caddy, Traefik, nginx, Dokploy, or a cloud load balancer.
  • SMTP credentials if you want Kanera to send email.
  • A plan for backing up PostgreSQL data and uploaded files.

Planning capacity

Kanera is lightweight at small-team scale. Its compose file does not set hard CPU or memory limits, and the migration service exits after startup. The default stack runs PostgreSQL, Valkey, two API replicas, a worker, the public API, MCP, and nginx.

Use these as starting points, then measure your own concurrent activity, files, integrations, and backup window:

Typical teamStarting capacityLocal diskNotes
Personal or lightly used1 vCPU, 1 GiB RAM10 GiBUse API_REPLICAS=1 and leave the optional monitoring profile off.
1 to 25 active users1-2 vCPU, 2 GiB RAM20 GiBComfortable for normal board activity, notifications, and light integrations.
26 to 100 active users2-4 vCPU, 4 GiB RAM40 GiBAdds headroom for concurrent activity, uploads, API traffic, webhooks, and database cache.
More than 100 active users4+ vCPU, 8+ GiB RAM80+ GiBLoad-test with representative data before launch, then scale API replicas and tune PostgreSQL from observed usage.

These are planning baselines, not hard user limits or measured capacity guarantees. Concurrent activity matters more than the number of registered accounts. File volume and retention usually drive disk requirements more than Kanera itself. Keep database and uploaded-file backups outside the server's primary disk, and alert on disk growth.

The optional Prometheus, Grafana, Loki, Alloy, and exporter monitoring profile adds several processes. The deployment guide estimates roughly 0.7 to 1.5 GiB of additional memory, depending on log volume and dashboard usage. Budget that separately or run monitoring on another host.

Deployment shape

The standard compose file runs these services:

ServicePurpose
postgresPostgreSQL database with persistent data in kanera_pgdata.
valkeyRequired Valkey instance for realtime fanout, presence, and shared rate limits.
migrateOne-shot database migration service that runs before app services start.
apiMain Kanera API and realtime server.
workerSingle background worker for schedulers, webhook delivery, notifications, cleanup, and realtime outbox fallback.
public-apiPublic integration API.
mcpMCP Streamable HTTP server backed by the public API.
webBuilt Kanera web app served by nginx.
db-backupOptional encrypted PostgreSQL backup scheduler.

The browser should connect to the web service. Do not expose the main api service directly; the web nginx container proxies app API and Socket.IO traffic internally.

Expose public-api only if you want external integrations. Expose mcp only if you want remote MCP clients to connect over HTTP.

Use separate domains for the app, public API, and MCP when you expose all three:

DomainServiceUse
kanera.example.comwebThe Kanera web app.
api.kanera.example.compublic-apiREST API, webhooks, and API reference.
mcp.kanera.example.commcpRemote MCP endpoint for AI clients.

The public API and MCP domains are optional. You can start with only the web app and add the others later.

Create the environment file

On the server, copy the example environment file:

cp .env.example .env

Set the required production values:

WEB_ORIGIN=https://kanera.example.com
COOKIE_DOMAIN=kanera.example.com
COOKIE_SECURE=true
KANERA_ENVIRONMENT=production

JWT_SECRET=<openssl rand -hex 32>
MEDIA_SIGNING_SECRET=<openssl rand -hex 32>
SECRETS_ENCRYPTION_KEY=<openssl rand -hex 32>

Keep these secrets stable across redeploys. Changing JWT_SECRET signs users out. Changing MEDIA_SIGNING_SECRET invalidates existing signed media URLs. SECRETS_ENCRYPTION_KEY protects stored integration secrets and should be distinct from JWT_SECRET.

Self-hosted mode is the default:

KANERA_DEPLOYMENT_MODE=self_hosted

Do not set hosted Stripe billing variables unless you are running a Kanera SaaS-style hosted deployment.

Configure email

SMTP is optional, but recommended for invites, notifications, verification, and operational use.

SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_PASSWORD=your-password
SMTP_FROM_NAME=Kanera

Leave email verification disabled until outbound mail is confirmed working:

EMAIL_VERIFICATION_ENABLED=false

After email is working, you can set EMAIL_VERIFICATION_ENABLED=true to require verification for signup, invite signup, and email changes.

Configure notifications

Kanera's notification drawer works without extra setup.

For email notifications, configure SMTP first. Users can then manage their own email channel and per-type email preferences from Profile settings -> Notifications.

For browser push notifications:

  1. Confirm Kanera is served over HTTPS.
  2. Open Profile settings -> Org as an organisation admin.
  3. Enable Allow browser push for this organisation.
  4. Ask users who want push alerts to open Profile settings -> Notifications, enable Allow push notifications, grant browser permission, and choose their per-type push preferences.

Personal notification settings after Kanera is running.

Push is device/browser specific. A user who wants alerts on multiple devices must enable push from each browser or installed PWA.

Configure Trello import attachment copying

Trello board JSON imports work without extra setup.

To let users import Trello file attachments into Kanera, configure a Trello API key:

TRELLO_API_KEY=your-trello-api-key

Create the key from Trello's Power-Up admin page at https://trello.com/power-ups/admin. No Power-Up capabilities are required; the Power-Up/app entry is only the Trello container for the API key. Users connect Trello during the import so Kanera can copy attachments for that import.

Publish ports

The default compose file keeps services private. If you are running Docker directly on a server, add a compose.override.yml file:

services:
web:
ports:
- "8080:80"

public-api:
ports:
- "3001:3001"

mcp:
ports:
- "3002:3002"

Then point your HTTPS reverse proxy at:

Public URLUpstream
https://kanera.example.comhttp://127.0.0.1:8080
https://api.kanera.example.comhttp://127.0.0.1:3001
https://mcp.kanera.example.comhttp://127.0.0.1:3002

Only publish public-api and mcp when you need them.

Trust proxy settings

Set these when Kanera is behind a trusted reverse proxy such as nginx, Traefik, Dokploy, or an ingress that sends the real client IP:

API_TRUST_PROXY=true
PUBLIC_API_TRUST_PROXY=true

API_TRUST_PROXY helps app authentication rate limits use the real client IP. PUBLIC_API_TRUST_PROXY does the same for public API rate limits.

Leave them false only when the service is directly internet-facing or directly Cloudflare-facing.

Start Kanera

Build and start the deployment:

docker compose up -d --build

The migration service runs pending database migrations once before api, worker, and public-api start. The MCP service starts after the public API health check passes.

Check the deployment

Open your web domain in a browser:

https://kanera.example.com

A Kanera board in the web app after deployment.

Useful checks:

docker compose ps
docker compose logs -f api
docker compose logs -f worker
docker compose logs -f public-api
docker compose logs -f mcp

Health checks:

curl https://kanera.example.com/api/health
curl https://api.kanera.example.com/health
curl https://mcp.kanera.example.com/health

The public API and MCP checks only apply if those services are exposed.

Public API

The public API service is used for integrations, webhooks, and API docs.

When exposed, the API reference is available at:

PathUse
/docsInteractive Scalar reference.
/swaggerSwagger UI reference.
/openapi.jsonOpenAPI document for SDK generation.

For example:

https://api.kanera.example.com/docs

See API for API keys, first requests, webhooks, and signature verification.

Workspace API settings for API keys and webhooks.

MCP

The MCP service lets AI clients connect to Kanera over Streamable HTTP.

When exposed, the endpoint is:

https://mcp.kanera.example.com/mcp

Set the public MCP URL when exposing it:

MCP_SERVER_PUBLIC_URL=https://mcp.kanera.example.com/mcp

In Docker Compose, keep the internal MCP-to-public-API URL as:

KANERA_PUBLIC_API_URL=http://public-api:3001

MCP clients authenticate with Kanera API keys using:

Authorization: Bearer kanera_live_...

Use a personal key from Profile settings -> API keys for a user's own AI client across their accessible boards. Use a workspace key from Workspace settings -> API for shared MCP clients or server-side automations pinned to one workspace.

OAuth for AI agents

To let compatible agents connect through a browser sign-in instead of an API key, tell Kanera its public OAuth URLs. Set the public API issuer on the public-api service:

PUBLIC_API_OAUTH_ISSUER=https://api.kanera.example.com

MCP_SERVER_PUBLIC_URL (set above) drives the MCP protected-resource metadata. With the bundled docker-compose.yml, two more variables are derived automatically: MCP_PUBLIC_URL (the MCP address shown to users) from MCP_SERVER_PUBLIC_URL, and the MCP service's OAUTH_ISSUER_URL from PUBLIC_API_OAUTH_ISSUER.

Route the OAuth discovery paths to the right service at your reverse proxy:

PathService
/.well-known/oauth-authorization-server, /oauth/*public-api
/.well-known/oauth-protected-resource, /mcpmcp

Self-hosted deployments have no plan restriction on agent connections. See Connect an AI agent for the full flow.

See Connect Kanera to your AI agent for client setup and MCP capabilities.

Workspace API settings where workspace API keys for MCP can be created.

Upload storage

By default, uploaded files are stored in the kanera_uploads Docker volume.

For S3-compatible storage, set:

S3_REGION=auto
S3_BUCKET=kanera
S3_ACCESS_KEY_ID=...
S3_SECRET_ACCESS_KEY=...
S3_ENDPOINT=https://s3.example.com
S3_PUBLIC_URL_PREFIX=https://cdn.example.com/kanera

When the required S3 values are set, S3 takes precedence over local upload storage.

Backups

Back up both:

DataLocation
PostgreSQL datakanera_pgdata Docker volume.
Uploaded fileskanera_uploads Docker volume, unless S3 storage is configured.

Manual PostgreSQL backup:

docker compose exec -T postgres pg_dump -U kanera kanera | gzip > kanera-$(date +%F).sql.gz

Kanera can also run encrypted full PostgreSQL backups to S3-compatible storage:

DB_BACKUPS_ENABLED=true
DB_BACKUP_ENCRYPTION_PASSPHRASE=<openssl rand -hex 32>
DB_BACKUP_TIMES_UTC=00:15,12:15,16:45
DB_BACKUP_RETENTION_DAYS=14
DB_BACKUP_S3_PREFIX=backups/postgres

The backup service compresses the dump, encrypts it with GPG symmetric AES-256, uploads it to S3, and prunes old backups after successful uploads. Store DB_BACKUP_ENCRYPTION_PASSPHRASE somewhere durable outside the deployment too; it is required to restore backups.

Updates

For a normal Docker deployment:

git pull
docker compose up -d --build api public-api mcp web

If a release includes database changes, the migration service runs before app services serve traffic.

For Dokploy, redeploy the application after pushing or pulling the latest code. Dokploy rebuilds from docker-compose.yml.

Dokploy notes

Dokploy is a good fit for Kanera because it can run the Docker Compose application and terminate HTTPS through Traefik.

In Dokploy:

  1. Create a project and application.
  2. Choose Docker Compose.
  3. Connect the Kanera repository.
  4. Set the compose file path to docker-compose.yml.
  5. Add the production environment variables.
  6. Deploy once.
  7. Add domains for web, public-api, and mcp as needed.

Use these domain routes:

DomainServiceContainer port
kanera.example.comweb80
api.kanera.example.compublic-api3001
mcp.kanera.example.commcp3002

Do not create a public domain for the main api service.

Scaling notes

The default deployment uses multiple app API replicas and one worker.

  • API_REPLICAS controls app API process count. Defaults to 2.
  • PUBLIC_API_REPLICAS controls public API process count. Defaults to 1.
  • MCP_REPLICAS controls MCP process count. Defaults to 1.
  • Keep worker at exactly 1.
  • Valkey is required for realtime fanout, presence, and shared rate limits.

Raise replicas only when the server has enough CPU, memory, and database connection capacity. If you raise API_REPLICAS, review PG_POOL_MAX and PostgreSQL max_connections.

Common issues

ProblemWhat to check
Users are signed out after login.Confirm COOKIE_SECURE=true, COOKIE_DOMAIN, and WEB_ORIGIN match the public HTTPS domain.
/api/health fails on the web domain.Confirm the domain routes to the web service on port 80, not directly to api.
Public API does not respond.Confirm the domain routes to public-api on port 3001.
MCP does not respond.Confirm the domain routes to mcp on port 3002, MCP_SERVER_PUBLIC_URL points at the public /mcp URL, and KANERA_PUBLIC_API_URL is http://public-api:3001 inside compose.
Rate limits affect everyone at once.Confirm API_TRUST_PROXY=true and PUBLIC_API_TRUST_PROXY=true when behind a trusted proxy.
Email verification blocks users.Leave EMAIL_VERIFICATION_ENABLED=false until SMTP is working.
Uploads disappear after redeploy.Confirm kanera_uploads is persistent or configure S3-compatible storage.