# Planka Kanban Board Playbook ## Overview `planka.yml` deploys [Planka](https://planka.app), a self-hosted kanban board application. The playbook provisions a Postgres database and the Planka app container via Docker Compose, generates and persists cryptographic secrets, and registers the stack on the `pangolin` overlay network for reverse-proxy access. ## Architecture ``` ┌─────────────────────────────────┐ ┌──────────────────────────┐ │ Target Docker Host │ │ Pangolin Server │ │ │ │ pangolin.wulfconsulting │ │ ┌─────────────┐ planka_net │ │ .cloud │ │ │ planka_app │◀──────────────▶│ │ │ │ │ (planka) │ :3000→1337 │ pangolin│ Routes traffic to │ │ └──────┬──────┘ network ─────────────▶│ planka. │ │ │ │ └──────────────────────────┘ │ ┌──────▼──────┐ │ │ │ planka- │ │ │ │ postgres │ │ │ │ (pg 16) │ │ │ └─────────────┘ │ │ │ │ /opt/stacks/planka/ │ │ ├── compose.yaml │ │ └── .secrets (mode 0600) │ └─────────────────────────────────┘ ``` ### Playbook structure | Section | Purpose | |---------|---------| | **vars** | Sets stack directory, Planka version, port, base URL, admin credentials, and secret-rotation flag | | **pre_tasks** | Validates admin password is not default, checks `planka_base_url` is set, verifies Docker is running, ensures `pangolin` Docker network exists | | **tasks** | Creates stack directory, generates/persists/reads cryptographic secrets, renders `compose.yaml`, deploys via `docker_compose_v2`, health-checks the HTTP endpoint, prints a deployment summary | | **handlers** | Restarts the Planka stack when `compose.yaml` changes | Secrets (`SECRET_KEY` and `INTERNAL_ACCESS_TOKEN`) are generated on first run and stored in `/opt/stacks/planka/.secrets` (root-only, mode `0600`). Subsequent runs re-use the persisted values unless `planka_rotate_secrets: true` is passed. ## Usage ### Required extra vars | Variable | Description | |----------|-------------| | `planka_admin_password` | Admin account password — must not be the default `ChangeMe123!` | | `planka_base_url` | Public URL Planka will be accessed at (used in auth cookies and links) | ### Optional extra vars | Variable | Default | Description | |----------|---------|-------------| | `planka_version` | `2.0.0-rc.3` | Planka image tag | | `planka_port` | `3000` | Host port mapped to the Planka container | | `planka_trust_proxy` | `false` | Set `true` when behind a reverse proxy (enables real-IP headers) | | `planka_token_expires_in` | `365` | Session token lifetime in days | | `planka_log_level` | `warn` | Planka log verbosity (`debug`, `info`, `warn`, `error`) | | `planka_db_name` | `planka` | Postgres database name | | `planka_admin_email` | `admin@example.com` | Admin account e-mail | | `planka_admin_name` | `Planka Admin` | Admin display name | | `planka_admin_username` | `admin` | Admin username | | `planka_rotate_secrets` | `false` | Set `true` to force regeneration of `SECRET_KEY` and `INTERNAL_ACCESS_TOKEN` | ### Deploy to a host ```bash ansible-playbook playbooks/planka.yml --limit myhost \ -e planka_admin_password=SuperSecret99! \ -e planka_base_url=https://planka.wulfconsulting.cloud ``` ### Override image version and port ```bash ansible-playbook playbooks/planka.yml --limit myhost \ -e planka_admin_password=SuperSecret99! \ -e planka_base_url=https://planka.wulfconsulting.cloud \ -e planka_version=latest \ -e planka_port=3001 ``` ### Rotate secrets on an existing deployment ```bash ansible-playbook playbooks/planka.yml --limit myhost \ -e planka_admin_password=SuperSecret99! \ -e planka_base_url=https://planka.wulfconsulting.cloud \ -e planka_rotate_secrets=true ``` ### Verify the containers are running ```bash ansible myhost -a "docker ps --filter name=planka" ``` ## Notes - **`planka_base_url` is required.** Planka embeds this URL in auth tokens and e-mail links; an incorrect value will break logins from behind a proxy. - **`planka_trust_proxy: true` is needed behind Pangolin/Traefik.** Without it, Planka sees the proxy's IP instead of the real client IP. - **Admin credentials are first-run only.** `DEFAULT_ADMIN_*` env vars only take effect when Planka initialises a fresh database. Changing them after the first deploy has no effect; use the Planka UI instead. - **Secrets are host-side persistent.** `/opt/stacks/planka/.secrets` survives container re-creation. Use `planka_rotate_secrets=true` only when intentionally invalidating all active sessions. - **`--limit` is required.** The playbook targets `all` hosts; always scope it to the intended host. - **Postgres data is in a named Docker volume** (`db-data`). Destroying the stack with `docker compose down -v` will wipe the database.