# portainer Docker container management UI — the "operator console" for cloud and edge. ## Access Portainer ingresses through nginx-proxy: `https://ops.wbd-rd.nl/`. No host port is published by default. For emergency ops (nginx down, etc.), uncomment the `ports:` block in `compose.yml` and `docker compose up -d portainer` to expose `:9443` and `:8000` directly. ## Auth Two layers: 1. **Keycloak SSO gate** — the nginx vhost calls `auth_request` against `oauth2-proxy-portainer` (Keycloak `wbd` realm, client `portainer-ce`). Anyone not in the realm is bounced to Keycloak login. 2. **Portainer local admin** — once past the SSO gate, Portainer asks for its own credentials. Portainer-CE has no native OIDC, so there's no way to skip this second step on CE. The admin user is **pre-seeded** at boot via `--admin-password=` (see compose), with the hash stored in `.env` as `PORTAINER_ADMIN_PASSWORD_HASH`. > Pre-seeding the admin bypasses Portainer's "5-minute setup window or lockout" behavior on fresh installs. ### Generating the bcrypt hash ```bash docker run --rm python:3.13-alpine sh -c \ "pip install -q bcrypt && python -c \"import bcrypt; print(bcrypt.hashpw(b'', bcrypt.gensalt()).decode())\"" ``` Double every `$` in the resulting hash before pasting into `.env` (`$2b$` → `$$2b$$`) — Compose interpolates single `$`. ## Edge-agent topology Port `8000` accepts reverse tunnels from edge sites running the `portainer/agent` image. The central cloud Portainer then manages every edge Docker host. Agent-side config lives under `sites//` once edge stacks are wired up. ## Networks - **mgmt** — Docker management plane - **app** — nginx-proxy reaches portainer:9443 from here - **Docker socket**: read-only mount; *effectively root-equivalent* on the host. The Keycloak SSO gate is what limits who can talk to Portainer. ## Volumes - `portainer-data` — Portainer DB (users, environments, stacks, settings) ## TODO - Edge-agent provisioning workflow per site (agent secret, registration call) - Map the `app-admin` Keycloak realm role to a Portainer team via the OAuth2 team-sync API (CE supports this) so promotion doesn't require manual Portainer-side admin clicks - Drop the direct `:9443` host port permanently (currently still commented but available)