Skip to content

Planka

Platform: TrueNAS Scale, Arcane Docker Management, Keycloak OIDC
Date: 23 March 2026
Planka version: 2.1.0 (Community Edition)


  1. Prerequisites
  2. Create TrueNAS dataset and directories
  3. Set permissions
  4. Create Keycloak client
  5. Docker Compose file (Arcane)
  6. Generate secrets
  7. Deploy in Arcane
  8. Create admin user
  9. Configure Pangolin reverse proxy
  10. Verify OIDC login
  11. Post-install: disable local auth (optional)
  12. Backup and restore
  13. Troubleshooting

Before starting, confirm the following are in place.

  • TrueNAS Scale with shell access
  • Arcane installed and operational for Docker Compose management
  • Keycloak running at https://auth.wighttrash.uk with the wighttrash realm configured
  • Pangolin reverse proxy managing planka.wighttrash.uk with a valid TLS certificate
  • DNS A/CNAME record for planka.wighttrash.uk pointing to your TrueNAS host (or Pangolin ingress)

Open the TrueNAS shell (or SSH in) and run the following.

Terminal window
# Create the base dataset directory (if the dataset /mnt/tank/configs/planka is already created via the TrueNAS UI, skip this)
mkdir -p /mnt/tank/configs/planka
# Create subdirectories for bind mounts
mkdir -p /mnt/tank/configs/planka/favicons
mkdir -p /mnt/tank/configs/planka/user-avatars
mkdir -p /mnt/tank/configs/planka/background-images
mkdir -p /mnt/tank/configs/planka/attachments
mkdir -p /mnt/tank/configs/planka/db-data

Planka runs as the node user inside the container (UID 1000, GID 1000). PostgreSQL runs as UID 999. Both need write access to their respective directories.

Terminal window
# Planka application directories
chown -R 1000:1000 /mnt/tank/configs/planka/favicons
chown -R 1000:1000 /mnt/tank/configs/planka/user-avatars
chown -R 1000:1000 /mnt/tank/configs/planka/background-images
chown -R 1000:1000 /mnt/tank/configs/planka/attachments
# PostgreSQL data directory
chown -R 999:999 /mnt/tank/configs/planka/db-data

If you have issues with permissions after deployment, the symptom is usually a container restart loop or write errors in the logs. Recheck ownership with ls -la /mnt/tank/configs/planka/.


Log in to Keycloak at https://auth.wighttrash.uk and select the wighttrash realm.

  1. Go to Clients and click Create client.
  2. Set the following:
    • Client type: OpenID Connect
    • Client ID: planka
  3. Click Next.
  4. On the Capability config page:
    • Client authentication: On
    • Authorization: Off
    • Standard flow: On (checked)
    • Direct access grants: Off
  5. Click Next.
  6. On the Login settings page:
    • Root URL: https://planka.wighttrash.uk
    • Home URL: https://planka.wighttrash.uk
    • Valid redirect URIs: https://planka.wighttrash.uk/oidc-callback
    • Valid post logout redirect URIs: https://planka.wighttrash.uk
    • Web origins: https://planka.wighttrash.uk
  7. Click Save.
  1. Go to the Credentials tab of the planka client.
  2. Copy the Client secret. You will need this for the Docker Compose file.
Section titled “4.3 Configure the groups claim (optional but recommended)”

This allows Planka to map Keycloak groups to Planka roles (Admin, Project Owner, Board User). If you skip this step, set OIDC_IGNORE_ROLES=true in the compose file and manage roles manually in Planka.

  1. Go to Clients > planka > Client scopes tab.
  2. Click planka-dedicated.
  3. Click Add mapper > By configuration > Group Membership.
  4. Configure the mapper:
    • Name: groups
    • Token Claim Name: groups
    • Full group path: Off
    • Add to ID token: On
    • Add to access token: On
    • Add to lightweight access token: Off
    • Add to userinfo: On
    • Add to token introspection: On
  5. Click Save.
  6. Create Keycloak groups to match the Planka roles you want to map:
    • planka-admin (maps to Planka Admin)
    • planka-project-owner (maps to Planka Project Owner)
  7. Add your users to the appropriate groups.

Users without a matching group claim are assigned the Board User role by default.


This compose file uses absolute bind mount paths under /mnt/tank/configs/planka/. No relative paths, no named Docker volumes.

Replace the three placeholder values marked with CHANGE_ME before deploying.

services:
planka:
image: ghcr.io/plankanban/planka:latest
restart: unless-stopped
volumes:
- /mnt/tank/configs/planka/favicons:/app/public/favicons
- /mnt/tank/configs/planka/user-avatars:/app/public/user-avatars
- /mnt/tank/configs/planka/background-images:/app/public/background-images
- /mnt/tank/configs/planka/attachments:/app/private/attachments
ports:
- "3050:1337"
environment:
# ── Core ──
- BASE_URL=https://planka.wighttrash.uk
- DATABASE_URL=postgresql://planka:CHANGE_ME_DB_PASSWORD@planka-db/planka
- SECRET_KEY=CHANGE_ME_SECRET_KEY
- TRUST_PROXY=true
# ── OIDC (Keycloak) ──
- OIDC_ISSUER=https://auth.wighttrash.uk/realms/wighttrash
- OIDC_CLIENT_ID=planka
- OIDC_CLIENT_SECRET=CHANGE_ME_KEYCLOAK_CLIENT_SECRET
- OIDC_SCOPES=openid profile email
- OIDC_ADMIN_ROLES=planka-admin
- OIDC_PROJECT_OWNER_ROLES=planka-project-owner
- OIDC_ROLES_ATTRIBUTE=groups
- OIDC_IGNORE_USERNAME=true
# ── Optional: disable local auth once OIDC is confirmed working ──
# - OIDC_ENFORCED=true
# ── Optional: debug OIDC (shows raw token payloads on login page) ──
# - OIDC_DEBUG=true
# ── Optional: SMTP for email notifications ──
# - SMTP_HOST=smtp.example.com
# - SMTP_PORT=587
# - SMTP_SECURE=true
# - SMTP_PASSWORD=your-smtp-password
# - SMTP_FROM="Planka" <[email protected]>
depends_on:
planka-db:
condition: service_healthy
planka-db:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- /mnt/tank/configs/planka/db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=planka
- POSTGRES_USER=planka
- POSTGRES_PASSWORD=CHANGE_ME_DB_PASSWORD
healthcheck:
test: ["CMD-SHELL", "pg_isready -U planka -d planka"]
interval: 10s
timeout: 5s
retries: 5

Important notes:

  • The planka-db service name is used in the DATABASE_URL. If you rename it, update the connection string.
  • TRUST_PROXY=true is required because Pangolin terminates TLS before forwarding to Planka.
  • OIDC_IGNORE_USERNAME=true is set because Keycloak’s preferred_username may contain characters that Planka’s username validation rejects (e.g., @).
  • The CHANGE_ME_DB_PASSWORD must be identical in both the planka and planka-db service environment sections.

Run these commands in TrueNAS shell to generate the values needed for the compose file.

Terminal window
# SECRET_KEY (64-character hex string)
openssl rand -hex 64
# DB password (32-character alphanumeric)
openssl rand -base64 32 | tr -dc 'A-Za-z0-9' | head -c 32

Copy the Keycloak client secret from section 4.2.

Replace the three CHANGE_ME placeholders in the compose file with these values.


  1. Open Arcane in your browser.
  2. Create a new stack or compose deployment.
  3. Paste the compose file from section 5 (with all three secrets replaced).
  4. Deploy the stack.
  5. Wait for both containers to show as healthy. The planka-db container must pass its healthcheck before planka will start.

Check the logs if either container fails to start:

Terminal window
# From TrueNAS shell, if Arcane does not show logs
docker logs planka
docker logs planka-db

After the containers are running, create the initial admin user. This is a one-time step.

Terminal window
docker exec -it planka npm run db:create-admin-user

You will be prompted for:

Password: (choose a strong password)
Name: Admin
Username (optional): admin

This local admin account is your fallback if OIDC breaks. Keep the credentials safe.

Note: If Arcane names the container differently (e.g., planka-planka-1), check with docker ps and adjust the command accordingly.


Add a route in Pangolin for planka.wighttrash.uk pointing to the Planka container.

  • Target: http://<truenas-ip>:3000 (or the Docker network address if Pangolin runs on the same host)
  • Protocol: HTTP (Pangolin handles TLS termination)
  • WebSocket support: Must be enabled. Planka uses WebSockets for real-time board updates. Without this, the UI will load but cards will not sync in real time.

If Pangolin has a “WebSocket” or “Upgrade” toggle for the route, enable it. If it uses custom headers, ensure these are passed:

Upgrade: $http_upgrade
Connection: "upgrade"

  1. Browse to https://planka.wighttrash.uk.
  2. You should see the standard Planka login form with an SSO button.
  3. Click SSO. You should be redirected to https://auth.wighttrash.uk/realms/wighttrash/protocol/openid-connect/auth?...
  4. Log in with your Keycloak credentials.
  5. On successful authentication, you are redirected back to Planka and logged in.

If the SSO button does not appear:

  • Check the Planka container logs for OIDC errors: docker logs planka
  • Verify OIDC_ISSUER is reachable from inside the container: docker exec planka wget -qO- https://auth.wighttrash.uk/realms/wighttrash/.well-known/openid-configuration
  • If the container cannot reach auth.wighttrash.uk, you may need to add a DNS entry or extra_hosts mapping in the compose file.

If login redirects but fails silently:

  • Set OIDC_DEBUG=true in the compose file, redeploy, and click the debug button on the login page to see the raw token payload.
  • Check that the redirect URI in Keycloak is exactly https://planka.wighttrash.uk/oidc-callback (no trailing slash).
  • Check that the client secret in the compose file matches what Keycloak shows.

If the username is rejected after login:

  • Confirm OIDC_IGNORE_USERNAME=true is set. Planka rejects usernames containing @, and Keycloak’s preferred_username often includes the email address.

11. Post-install: disable local auth (optional)

Section titled “11. Post-install: disable local auth (optional)”

Once you have confirmed OIDC works for both users, you can optionally force all authentication through Keycloak by uncommenting this line in the compose file:

- OIDC_ENFORCED=true

Redeploy after making this change. The local login form will be hidden and all users must authenticate via Keycloak.

Warning: If Keycloak goes down while OIDC_ENFORCED=true, nobody can log in to Planka. Keep the local admin credentials as a break-glass option. To use them, temporarily remove OIDC_ENFORCED=true and redeploy.


Terminal window
# Database dump
docker exec planka-db pg_dump -U planka planka > /mnt/tank/configs/planka/backup-$(date +%Y%m%d).sql
# File attachments (already on the dataset, but tar for offsite)
tar czf /mnt/tank/configs/planka/attachments-backup-$(date +%Y%m%d).tar.gz \
-C /mnt/tank/configs/planka attachments user-avatars background-images favicons
Terminal window
# Stop Planka (keep database running)
docker stop planka
# Restore database
cat /mnt/tank/configs/planka/backup-YYYYMMDD.sql | docker exec -i planka-db psql -U planka planka
# Restore files
tar xzf /mnt/tank/configs/planka/attachments-backup-YYYYMMDD.tar.gz -C /mnt/tank/configs/planka
# Fix permissions
chown -R 1000:1000 /mnt/tank/configs/planka/favicons /mnt/tank/configs/planka/user-avatars /mnt/tank/configs/planka/background-images /mnt/tank/configs/planka/attachments
# Start Planka
docker start planka
Terminal window
# Take a backup first (see above)
# Pull latest image
docker pull ghcr.io/plankanban/planka:latest
# Redeploy via Arcane (or docker compose up -d)

SymptomLikely causeFix
Container restart loopPermission denied on bind mountsRe-run chown commands from section 3
White screen after loginWebSocket not proxiedEnable WebSocket support in Pangolin route
SSO button missingOIDC env vars not set or container not restartedCheck env vars, redeploy in Arcane
OIDC redirect failsRedirect URI mismatch in KeycloakSet to exactly https://planka.wighttrash.uk/oidc-callback
”Invalid username” after OIDC loginUsername contains @Set OIDC_IGNORE_USERNAME=true
Container cannot reach KeycloakDNS resolution inside containerAdd extra_hosts: - "auth.wighttrash.uk:<ip>" to the planka service, or fix container DNS
Database connection refusedplanka-db not healthy yet or password mismatchCheck healthcheck status; confirm CHANGE_ME_DB_PASSWORD matches in both services
Cards do not sync in real timeWebSocket blockedConfirm Pangolin passes Upgrade and Connection headers
OIDC_DEBUG=true shows empty groups claimGroup mapper not configuredFollow section 4.3 to add the groups mapper in Keycloak
Roles not mapping from KeycloakClaims source mismatchIf groups are only in the ID token, add OIDC_CLAIMS_SOURCE=id_token to the compose file
Terminal window
# Check container status
docker ps --filter name=planka
# View Planka logs
docker logs -f planka
# View database logs
docker logs -f planka-db
# Test OIDC discovery from inside the container
docker exec planka wget -qO- https://auth.wighttrash.uk/realms/wighttrash/.well-known/openid-configuration
# Interactive shell inside Planka container
docker exec -it planka sh