---
okf: "0.1"
type: service
visibility: private
status: active
updated: 2026-06-17
links: []
---

# Vikunja

Self-hosted task management. Runs on the **PIHA** node with a dedicated
PostgreSQL backend, exposed publicly at `https://vikunja.okit.pl` via the npm
reverse proxy on PIHA. Login is via Forgejo OIDC.

## Stack

| Container   | Image                  | Purpose                          |
|-------------|------------------------|----------------------------------|
| `vikunja`   | `vikunja/vikunja:latest` | App + API (port 3456)          |
| `vikunja-db`| `postgres:16-alpine`   | PostgreSQL (service alias `db`)  |

## Data (do not move)

Persistent state lives in pre-existing Docker named volumes — these are pinned
by name so the live data survives cutover:

- `vikunja_vikunja_db`  → `/var/lib/postgresql/data`
- `vikunja_vikunja_files` → `/app/vikunja/files`

## Configuration

- `config.yml` — committed, **secret-free**. Holds OIDC provider metadata.
- `.env` — **gitignored**. Copy from `env.example` and fill with the real
  live values (must be identical to the running instance):
  - `POSTGRES_PASSWORD` / `VIKUNJA_DATABASE_PASSWORD` (same value)
  - `VIKUNJA_SERVICE_JWTSECRET`
  - `VIKUNJA_AUTH_OPENID_PROVIDERS_FORGEJO_CLIENTSECRET`

## Notes

- `forgejo.okit.pl` is pinned via `extra_hosts` to `192.168.31.5` (npm on PIHA)
  so OIDC discovery resolves over the LAN, avoiding flaky public DNS.
- Both `redirecturl` and the provider `authurl` MUST keep their trailing slash —
  the `authurl` must match the OIDC issuer exactly or discovery fails.

## Cutover checklist

1. `git pull` on PIHA.
2. Create `services/vikunja/.env` from `env.example` with the real values.
3. Confirm the named volumes exist: `docker volume ls | grep vikunja_vikunja`.
4. `docker compose -f services/vikunja/docker-compose.yml up -d`.
5. Verify: `./healthcheck.sh` and a test OIDC login.
