Keycloak
Identity and access management
| Item | Detail |
|---|---|
| Compose file | /opt/keycloak/docker-compose.yml |
| Database | PostgreSQL 16 (container: keycloak-postgres) |
| Reverse proxy | Traefik (Pangolin stack) via dynamic_config.yml |
| Image | keycloak-local:latest (optimised build from quay.io/keycloak/keycloak:26.4.7) |
Architecture
Section titled “Architecture”Keycloak runs on the Netcup VPS alongside Pangolin. Cloudflare terminates TLS at the edge. Traefik routes auth.wighttrash.uk to the Keycloak container on port 8080. Keycloak runs plain HTTP internally, which is correct for an edge-terminated setup.
File layout
Section titled “File layout”/opt/keycloak/├── docker-compose.yml├── .env <- secrets, chmod 600, never commit├── Dockerfile <- optimised build image└── data/ └── import/Dockerfile
Section titled “Dockerfile”An optimised build image is used for fast startup. Rebuild when upgrading Keycloak or changing build-time options.
FROM quay.io/keycloak/keycloak:26.4.7 AS builder
ENV KC_DB=postgresENV KC_HEALTH_ENABLED=trueENV KC_METRICS_ENABLED=trueENV KC_FEATURES=token-exchange
RUN /opt/keycloak/bin/kc.sh build
FROM quay.io/keycloak/keycloak:26.4.7COPY --from=builder /opt/keycloak/ /opt/keycloak/
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]Rebuild command:
cd /opt/keycloakdocker build -t keycloak-local:latest .Realm setup
Section titled “Realm setup”The master realm is used for admin access only. All applications use the wighttrash realm.
| Realm | Purpose |
|---|---|
| master | Admin console access only |
| wighttrash | All application authentication (Immich, Jellyfin, Pangolin, Docs wiki) |
Do not register applications in the master realm.
Admin accounts
Section titled “Admin accounts”Two accounts exist following a break-glass pattern.
| Account | Realm | Auth method | Purpose |
|---|---|---|---|
| kcadmin | master | Username/password + TOTP | Break-glass - use if Keycloak social login is unavailable |
| [email protected] | master | Social login (Entra ID) | Day-to-day admin access |
Day-to-day admin work uses [email protected] via https://auth.wighttrash.uk/admin/master/console. The kcadmin account is kept as a fallback in case Keycloak’s own authentication is unavailable.
Authentication configuration
Section titled “Authentication configuration”Social login providers
Section titled “Social login providers”Both providers are configured in the wighttrash realm under Identity Providers.
| Provider | Alias | Trust email | Sync mode | First login flow |
|---|---|---|---|---|
| On | Force | auto link existing only | ||
| Microsoft (Entra) | microsoft | On | Force | auto link existing only |
Restricting access to approved users only
Section titled “Restricting access to approved users only”The auto link existing only flow is a custom Basic flow with two steps, both Required.
Step 1. Detect existing broker user - checks whether a Keycloak account with the same email exists in the realm. If no match is found, the flow fails and the user is blocked. No new accounts are created.
Step 2. Automatically set existing user - links the social login to the matched Keycloak account with no further challenge.
To allow a new user to sign in via social, create them in the wighttrash realm first under Users, set Email verified to On, and do not set a password. The social provider will be linked automatically on first login.
Registered OIDC clients
Section titled “Registered OIDC clients”| Client ID | Name | Auth method | Redirect URIs | Post logout URI |
|---|---|---|---|---|
| immich | Immich | Social (Google / Microsoft via Keycloak) |
| https://photos.wighttrash.uk |
| jellyfin | Jellyfin | Social (Google / Microsoft via Keycloak) |
| https://media.wighttrash.uk/ |
| pangolin | Pangolin | Social (Google / Microsoft) + break-glass password / MFA |
| https://pangolin.wighttrash.uk |
| docs-wiki | Docs Wiki (Cloudflare Access) | Social (Google / Microsoft via Keycloak) |
| https://docs.wighttrash.uk |
| planka | Planka | Keycloak OIDC (social login) |
| https://planka.wighttrash.uk |
| web | OpenCloud Web | Keycloak OIDC / PKCE S256 (realm roles via opencloud-roles mapper) |
| https://cloud.wighttrash.uk |
| OpenCloudAndroid | OpenCloud Android | Keycloak OIDC / PKCE S256 |
| - |
| OpenCloudDesktop | OpenCloud Desktop | Keycloak OIDC / PKCE S256 |
| - |
| OpenCloudIOS | OpenCloud iOS | Keycloak OIDC / PKCE S256 |
| oc://ios.opencloud.eu |
All clients are confidential (client authentication on, standard flow only).
OIDC discovery endpoint
Section titled “OIDC discovery endpoint”https://auth.wighttrash.uk/realms/wighttrash/.well-known/openid-configurationHardening checklist
Section titled “Hardening checklist”| Item | Status |
|---|---|
| Bootstrap admin deleted, permanent admin created | Done |
| User self-registration disabled | Done |
| Email verification enabled | Done |
| Login with email enabled | Done |
| Brute force detection enabled (max 5 failures, 15 min lockout) | Done |
| Session timeouts configured (SSO 8h, access token 5 min, refresh 30 min) | Done |
| Port 9000 (health/metrics) not exposed publicly | Done |
| Port 8080 (HTTP) not exposed directly - Traefik only | Done |
| .env is chmod 600 | Done |
| Image pinned to 26.4.7 | Done |
PostgreSQL backup and restore
Section titled “PostgreSQL backup and restore”# Manual dumpdocker exec keycloak-postgres pg_dump -U keycloak keycloak \ > /opt/keycloak/backup-$(date +%Y%m%d).sql
# Restoredocker exec -i keycloak-postgres psql -U keycloak keycloak \ < /opt/keycloak/backup-YYYYMMDD.sqlUseful commands
Section titled “Useful commands”# View logsdocker logs -f keycloak
# Check health (from inside VPS)curl -s http://localhost:9000/health/ready
# Restart stackcd /opt/keycloak && docker compose restart
# Rebuild image (after version change)cd /opt/keycloak && docker build -t keycloak-local:latest .Upgrading
Section titled “Upgrading”Step 1. Update the version tag in /opt/keycloak/Dockerfile.
Step 2. Back up PostgreSQL (see above).
Step 3. Rebuild the image:
docker build -t keycloak-local:latest .Step 4. Start the updated stack:
docker compose up -dStep 5. Watch logs to confirm startup:
docker logs -f keycloakStep 6. Verify the OIDC discovery endpoint is responding:
curl -s https://auth.wighttrash.uk/realms/wighttrash/.well-known/openid-configurationTroubleshooting
Section titled “Troubleshooting”Keycloak will not start. Check logs with docker logs keycloak --tail 100. Common causes are database not ready or misconfigured KC_HOSTNAME.
503 from Traefik. Confirm Keycloak is running (docker ps) and that the IP in dynamic_config.yml matches the container’s current IP on the pangolin network (docker network inspect pangolin).
Social login denied with “invalid username or password”. The user’s email does not exist in the wighttrash realm. Create the user in the Admin Console first.
Locked out of admin console. Go directly to https://auth.wighttrash.uk/admin/master/console and sign in with kcadmin. This bypasses the wighttrash realm entirely.