> ## Documentation Index
> Fetch the complete documentation index at: https://kaneo.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Migration guide

> How to upgrade from the two-container setup (api + web) to the combined kaneo container introduced in v2.6.0.

## What changed in v2.6.0

This release replaces the separate `api` and `web` containers with a single `kaneo` container. nginx runs on port 5173 and proxies `/api/` requests to the internal Node API. Everything else (the database, volumes, environment variables) works the same.

Three areas require changes when upgrading:

1. Docker Compose: replace the `api` and `web` services with `kaneo`
2. Environment variables: `KANEO_API_URL` and `DATABASE_URL` are now optional
3. Helm chart: all `api.*` and `web.*` values moved under `kaneo.*` (chart version 0.3.0)

***

## Docker Compose

### Before

```yml theme={"theme":{"light":"min-light","dark":"min-dark"}}
services:
  postgres:
    image: postgres:16-alpine
    env_file:
      - .env
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  api:
    image: ghcr.io/usekaneo/api:latest
    ports:
      - "1337:1337"
    env_file:
      - .env
    depends_on:
      - postgres
    restart: unless-stopped

  web:
    image: ghcr.io/usekaneo/web:latest
    ports:
      - "5173:5173"
    env_file:
      - .env
    depends_on:
      - api
    restart: unless-stopped

volumes:
  postgres_data:
```

### After

```yml theme={"theme":{"light":"min-light","dark":"min-dark"}}
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 \"$${POSTGRES_USER:-kaneo}\" -d \"$${POSTGRES_DB:-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:
```

Remove the `api` and `web` service blocks and add the `kaneo` service. The `postgres` service is unchanged except for the added healthcheck, which `kaneo` waits for before starting.

***

## Environment variables

### KANEO\_API\_URL is now optional

Previously both `KANEO_CLIENT_URL` and `KANEO_API_URL` were required. Now `KANEO_API_URL` is derived automatically from `KANEO_CLIENT_URL`:

```
KANEO_API_URL = KANEO_CLIENT_URL + "/api"
```

Remove `KANEO_API_URL` from your `.env` unless you need to override it (for example, when a reverse proxy changes the API path).

**Before:**

```env theme={"theme":{"light":"min-light","dark":"min-dark"}}
KANEO_CLIENT_URL=https://kaneo.example.com
KANEO_API_URL=https://kaneo.example.com/api
```

**After:**

```env theme={"theme":{"light":"min-light","dark":"min-dark"}}
KANEO_CLIENT_URL=https://kaneo.example.com
# KANEO_API_URL is set automatically to https://kaneo.example.com/api
```

### DATABASE\_URL is now optional

For the bundled image, `DATABASE_URL` is derived from `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, and the default Compose hostname if you leave it unset:

```
postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
```

If you were setting `DATABASE_URL` explicitly with the same values, you can remove it.
Keep it if you use an external database, a non-default hostname, or a host-native API process that should connect through `localhost` instead of the Compose hostname.

**Before:**

```env theme={"theme":{"light":"min-light","dark":"min-dark"}}
POSTGRES_DB=kaneo
POSTGRES_USER=kaneo
POSTGRES_PASSWORD=changeme
DATABASE_URL=postgresql://kaneo:changeme@postgres:5432/kaneo
```

**After:**

```env theme={"theme":{"light":"min-light","dark":"min-dark"}}
POSTGRES_DB=kaneo
POSTGRES_USER=kaneo
POSTGRES_PASSWORD=changeme
# DATABASE_URL is derived automatically
```

### AUTH\_SECRET fallback behavior

If `AUTH_SECRET` is not set, the container generates a random 64-character hex secret at startup and prints a warning to stderr. This means sessions will not survive container restarts.

Set a stable secret to avoid losing active sessions on restart:

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
openssl rand -hex 32
```

```env theme={"theme":{"light":"min-light","dark":"min-dark"}}
AUTH_SECRET=your_generated_secret_here
```

***

## Helm chart (0.2.0 → 0.3.0)

Chart version 0.3.0 is a breaking change. All `api.*` and `web.*` value keys have moved under `kaneo.*`.

### Changed value keys

| Old key                               | New key                                    |
| ------------------------------------- | ------------------------------------------ |
| `api.image.repository`                | `kaneo.image.repository`                   |
| `api.image.tag`                       | `kaneo.image.tag`                          |
| `api.image.pullPolicy`                | `kaneo.image.pullPolicy`                   |
| `api.service.type`                    | `kaneo.service.type`                       |
| `api.service.port`                    | `kaneo.service.port`                       |
| `api.resources`                       | `kaneo.resources`                          |
| `api.env.clientUrl`                   | `kaneo.env.clientUrl`                      |
| `api.env.authSecret`                  | `kaneo.env.authSecret`                     |
| `api.env.existingSecret`              | `kaneo.env.existingSecret`                 |
| `api.env.disableRegistration`         | `kaneo.env.disableRegistration`            |
| `api.env.disablePasswordRegistration` | `kaneo.env.disablePasswordRegistration`    |
| `api.env.database`                    | `kaneo.env.database`                       |
| `api.livenessProbe`                   | `kaneo.livenessProbe`                      |
| `api.readinessProbe`                  | `kaneo.readinessProbe`                     |
| `web.*`                               | removed, web is bundled in the kaneo image |

### Example values migration

**Before (`values.yaml`):**

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
api:
  image:
    repository: ghcr.io/usekaneo/api
    tag: "2.5.0"
  service:
    type: ClusterIP
    port: 1337
  env:
    clientUrl: "https://kaneo.example.com"
    authSecret: "your-secret-here"

web:
  image:
    repository: ghcr.io/usekaneo/web
    tag: "2.5.0"
  service:
    type: ClusterIP
    port: 5173
```

**After (`values.yaml`):**

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
kaneo:
  image:
    repository: ghcr.io/usekaneo/kaneo
    tag: "2.6.0"
  service:
    type: ClusterIP
    port: 5173
  env:
    clientUrl: "https://kaneo.example.com"
    authSecret: "your-secret-here"
```

### Upgrade command

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
helm upgrade kaneo kaneo/kaneo \
  --version 0.3.0 \
  --values your-values.yaml \
  --namespace kaneo
```

If you store values in a file, update the keys before running the upgrade. Helm will reject unknown keys and the deployment will fail if `api.*` or `web.*` keys remain.

***

## Minimum working configuration

After upgrading, a minimal `.env` for Docker Compose requires three values:

```env theme={"theme":{"light":"min-light","dark":"min-dark"}}
KANEO_CLIENT_URL=http://localhost:5173
POSTGRES_PASSWORD=changeme
AUTH_SECRET=replace_with_output_of_openssl_rand_hex_32
```

Generate a stable secret with `openssl rand -hex 32` and keep it persistent, or active sessions will be invalidated after a container restart.

`POSTGRES_DB` and `POSTGRES_USER` default to `kaneo` if not set. `KANEO_API_URL` and `DATABASE_URL` are derived automatically.
