# Self-hosted OIDC identity provider (Keycloak)

Source: https://docs.quake.ai/resources/iac-templates/auth-oidc
Markdown: https://docs.quake.ai/resources/iac-templates/auth-oidc.md

---

# Self-hosted OIDC identity provider (Keycloak)

This pattern composes Compute, Network, and Block Storage into a self-hosted identity provider you run on infrastructure you control.

## What this template does

Provisions a single instance running [Keycloak](https://www.keycloak.org), an open-source identity and access management server (a self-hosted alternative to Clerk or Auth0). Your application authenticates against realms and clients you own:

- Compute instance that runs Keycloak in Docker alongside a bundled PostgreSQL (4 vCPU and 4 GiB RAM)
- Private network, subnet, router, port, and security group; a floating IP for public access
- A block volume mounted at `/var/lib/docker`, so the realm, client, and user data lives on a volume you can grow rather than on the boot disk
- cloud-init installs Docker Engine and brings up Keycloak in `start-dev` bootstrap mode against the bundled PostgreSQL

The bootstrap admin password and the database password are generated on first boot and written to `/opt/auth-oidc/.env`; no credential ships with this template.

## Keycloak's HTTPS-before-real-login requirement

Keycloak's production `start` command refuses to issue real tokens over plain HTTP: it expects a certificate on the server itself, or `KC_HTTP_ENABLED=true` plus `KC_PROXY_HEADERS=xforwarded` when a reverse proxy terminates TLS in front of it. This template starts in `start-dev` bootstrap mode, which tolerates plain HTTP so you can create your first realm and client without a domain in hand yet. The bootstrap server is gated to `app_allowed_cidr` (the private network by default); it is not the path real users sign in through. Switch to `start` with a domain and a reverse proxy before pointing a real application at this identity provider.

## Why Keycloak over Authentik

This template leads with Keycloak because it is the most widely deployed open-source identity server, has the longest track record in enterprise and Kubernetes environments, and its realm/client model maps directly onto the OIDC concepts most application frameworks already expect. [Authentik](https://goauthentik.io) is a reasonable alternative if you want a more opinionated, modern admin UI and do not need Keycloak's broader protocol surface (SAML, Kerberos brokering, fine-grained authorization services).

## Parameters

| Parameter | Description | Default |
| --- | --- | --- |
| `key_name` | SSH keypair name (must already exist) | No default |
| `flavor_name` | Instance size (Keycloak plus PostgreSQL runs on 4 vCPU / 4 GiB) | `s1a.medium` |
| `image_name` | Operating system image | `Ubuntu-24.04` |
| `app_name` | Display name prefix for resources | `auth-oidc` |
| `volume_size` | Block volume size in GiB, mounted at `/var/lib/docker` | `20` |
| `external_network` | External network for floating IP allocation | `PublicStatic` |
| `private_cidr` | CIDR for the private subnet | `10.48.0.0/24` |
| `app_allowed_cidr` | CIDR allowed to reach Keycloak on port 8080 | `10.48.0.0/24` |

## Finish setup after apply

cloud-init starts Keycloak in `start-dev` mode against the bundled PostgreSQL and writes the generated secrets to `/opt/auth-oidc/.env`. Read the bootstrap admin password over SSH:

```bash
sudo grep KC_BOOTSTRAP_ADMIN_PASSWORD /opt/auth-oidc/.env
```

Sign in to the admin console at `http://YOUR_FLOATING_IP:8080`, create a realm and a client, and register your application's redirect URIs. When you are ready for real traffic, move to production:

1. Point a domain's DNS A record at the floating IP and put a reverse proxy (Caddy or Nginx) in front for HTTPS on 443.
2. Edit `/opt/auth-oidc/.env`: set `KC_HOSTNAME` to your public HTTPS address, `KC_PROXY_HEADERS=xforwarded`, and `KC_HTTP_ENABLED=true`.
3. Change the `keycloak` service's `command` in `/opt/auth-oidc/docker-compose.yml` from `start-dev` to `start`, then run `sudo docker compose up -d`.

## Access and security

Keycloak listens on port 8080 over plain HTTP in bootstrap mode. The security group restricts 8080 to `app_allowed_cidr`, which defaults to the private network only. Ports 80 and 443 stay open for the reverse proxy you add before going to production; they carry no traffic until then.

## When to use this pattern

Run a self-hosted OIDC identity provider for one or more applications on a host you operate. Keycloak suits a team that wants realms, clients, and social-login brokering without a per-monthly-active-user SaaS bill. The bundled PostgreSQL suits a single identity provider; to run it separately, point `KC_DB_URL` at a [self-managed PostgreSQL](/resources/iac-templates/self-managed-postgres) instance.

## Estimated cost

<PricingCompanion
  components={[
    { kind: "template", slug: "auth-oidc", required: true },
  ]}
/>

## Template source

<TemplateSource slug="auth-oidc" />

<TemplateResourceMap template="auth-oidc" format="opentofu" />

## Customize this pattern

- [Customize a template's image and flavor](/docs/automation/how-to/customize-template-image-flavor)
- [Add a block volume to a template](/docs/automation/how-to/add-volume-to-template)
- [Parameterize a template with a tfvars file](/docs/automation/how-to/parameterize-template-tfvars)

## See also

- [Self-managed PostgreSQL](/resources/iac-templates/self-managed-postgres)
- [Outline](/resources/iac-templates/outline-docs): an existing OIDC consumer that wires against an identity provider like this one
- [Self-hosted vibecode stack](/resources/solutions/self-hosted-vibecode-stack)
