Dev vs Production Mode
Keycloak has two startup modes: start-dev for development and start for production. They are not interchangeable — start-dev makes several convenience compromises that are unsafe in a real environment. Understanding the difference is important before you move beyond local learning.
start-dev: development mode
Section titled “start-dev: development mode”start-dev is optimised for getting started quickly. It uses an embedded H2 in-memory database (data is lost on restart), enables HTTP (no TLS), disables hostname verification, and relaxes several security checks. Use it only on localhost when learning Keycloak.
docker run --name keycloak -p 8080:8080 \ -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \ -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \ quay.io/keycloak/keycloak:latest start-devstart: production mode
Section titled “start: production mode”start is the production command. It requires an external database, a fixed hostname, and HTTPS (or a configured reverse proxy). Keycloak will refuse to start in production mode without a valid hostname and TLS configuration. Key environment variables:
| Environment variable | Purpose | Example |
|---|---|---|
KC_DB | Database vendor | postgres |
KC_DB_URL | JDBC connection URL | jdbc:postgresql://db:5432/keycloak |
KC_DB_USERNAME | DB username | keycloak |
KC_DB_PASSWORD | DB password | changeme |
KC_HOSTNAME | Public hostname for Keycloak | auth.example.com |
KC_PROXY_HEADERS | Trust proxy headers (xforwarded or forwarded) | xforwarded |
KC_HTTP_ENABLED | Allow HTTP (needed behind a TLS-terminating proxy) | true |
docker run --name keycloak -p 8080:8080 \
-e KC_DB=postgres \
-e KC_DB_URL=jdbc:postgresql://db:5432/keycloak \
-e KC_DB_USERNAME=keycloak \
-e KC_DB_PASSWORD=changeme \
-e KC_HOSTNAME=auth.example.com \
-e KC_PROXY_HEADERS=xforwarded \
-e KC_HTTP_ENABLED=true \
quay.io/keycloak/keycloak:latest startOptimized build
Section titled “Optimized build”For production, Keycloak recommends running kc.sh build (or kc.bat build) inside the image before starting. This pre-processes configuration and significantly reduces startup time. A typical production Dockerfile uses a two-stage build: one stage to run kc.sh build, another to copy the built distribution and run kc.sh start.
# Stage 1: buildFROM quay.io/keycloak/keycloak:latest AS builderRUN /opt/keycloak/bin/kc.sh build --db=postgres
# Stage 2: runFROM quay.io/keycloak/keycloak:latestCOPY --from=builder /opt/keycloak/ /opt/keycloak/ENTRYPOINT ["/opt/keycloak/bin/kc.sh", "start"]