KeycloakをDockerで動かすだけなら、公式のコンテナイメージにstart-devを渡す1行で済みます。ただしこの起動方法は開発用で、本番ではビルド済みイメージ、外部のデータベース、TLSを終端するリバースプロキシ、ヘルスチェックの4つを自分で組むことが必要です。本記事では、2026年11月5日時点の最新版Keycloak 26.8.1を前提に、Dockerfileでのビルド、Docker ComposeでPostgreSQLとnginxを並べる定義、KC_HOSTNAMEとKC_PROXY_HEADERSの設定、curlの入っていないイメージでのhealthcheckの書き方を、コピーして使える設定例つきで解説します。
まとめ:KeycloakのDocker運用はビルド済みイメージとプロキシ配下のstartで組む
本番でKeycloakをDockerに載せるなら、Dockerfileでkc.sh buildを済ませたイメージを作り、start --optimizedで起動します。データベースはPostgreSQLを別コンテナか外部のマネージドサービスに置き、TLSはnginxなどのリバースプロキシで終端させます。このときKeycloak側にはKC_HOSTNAMEに公開URLを、KC_PROXY_HEADERSにxforwardedを必ず設定してください。
ヘルスチェックとメトリクスは管理ポート9000番に出ます。この番号はプロキシで外に出しません。公式イメージにはcurlが無いため、Composeのhealthcheckはbashの/dev/tcpで/health/readyを確かめる形にします。
1台のComposeで足りるのは、認証基盤が数分止まっても業務が続く社内向けの用途までです。止められない顧客向けのログインを載せるなら、2台以上の構成かIDaaSを選びます。
Keycloak 26.8.1のdocker runによる開発起動手順
最初に、公式の手順どおりに開発モードで起動し、何が足りないのかを確かめます。Keycloakの機能や他製品との違いはKeycloakとは?Oktaとの違いと連携手順で整理しています。
start-devの起動コマンドとbootstrap用の一時管理者の扱い
KeycloakのコンテナイメージはQuay.ioのkeycloak/keycloakで配布されています。公式のDocker入門に載っている起動コマンドは次のとおりです。
docker run -p 127.0.0.1:8080:8080 \
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:26.8.1 start-dev
起動後にhttp://localhost:8080/adminを開くと、管理コンソールに入れます。KC_BOOTSTRAP_ADMIN_*で作られるのは一時的な管理者です。コンテナの外からは、この環境変数を使わない限り最初の管理者を作れません。ログインしたら正規の管理者を作り、一時管理者は削除します。最初に存在するレルムはmasterだけで、公式はこれをKeycloak自体の管理専用とし、アプリ用には別のレルムを作るよう案内しています。
start-devを本番に使えない理由とstartで増える必須設定
start-devはHTTPを許可し、ホスト名の検証を緩め、データを組み込みのdev-fileに保存します。キャッシュも分散キャッシュのガイドのとおりlocalに固定され、複数台で動かす前提がありません。
本番モードのstartに切り替えると、次の設定が無い限り起動しないか、外から正しく使えません。
- ホスト名(
KC_HOSTNAME):トークンやリダイレクトに書かれる公開URL - TLS:Keycloak自身に証明書を持たせるか、プロキシで終端して
KC_HTTP_ENABLED=trueにする - データベース:PostgreSQLなどの本番向けDB
- プロキシのヘッダー(
KC_PROXY_HEADERS):プロキシ配下に置く場合
このうちデータベースの選び方と接続プールの設定値は、Keycloakのデータベース設定と使い方で詳しく扱っています。本記事は残りのDocker固有の部分に絞ります。
Dockerfileのkc.sh buildで起動時間と設定差を減らす
公式イメージをそのままstartで起動することもできますが、その場合は起動のたびに内部でビルドが走ります。コンテナのガイドは、ビルドを済ませたイメージを作ってから起動する方法を勧めています。
ビルドオプションと起動オプションの違いと–optimizedのエラー条件
Keycloakの設定には、kc.sh buildのときに決めるビルドオプションと、起動時に渡すオプションの2種類があります。設定のガイドはデータベースの種類--dbをビルドオプションの例に挙げ、ヘルスチェックのガイドはhealth-enabledもビルド時に指定するものとしています。
start --optimizedは、ビルド済みのイメージだと見なして起動時のビルドを省きます。起動時に渡したビルドオプションの値がビルド時と同じなら黙って無視され、違えばエラーで停止する仕組みです。つまりKC_DBをビルド時にpostgresにしておけば、本番で誤って別のDBを指定しても起動前に気づけます。ビルドオプションは平文で保存されるため、パスワードのような秘密情報をビルド時に渡してはいけません。
2段階ビルドのDockerfileとプロバイダーJARを入れる位置
コンテナのガイドの例から、検証用の自己署名証明書の生成を除いたものが次のDockerfileです。builder段階でビルドオプションを決めてkc.sh buildを実行し、結果の/opt/keycloak/だけを次の段階へ写します。
# Dockerfile:ビルド済みの Keycloak イメージを作る
FROM quay.io/keycloak/keycloak:26.8.1 AS builder
# ビルドオプション(秘密情報はここに書かない)
ENV KC_DB=postgres
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
# 独自の認証拡張(SPI)がある場合は build の前に置く
# COPY providers/*.jar /opt/keycloak/providers/
WORKDIR /opt/keycloak
RUN /opt/keycloak/bin/kc.sh build
FROM quay.io/keycloak/keycloak:26.8.1
COPY --from=builder /opt/keycloak/ /opt/keycloak/
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]
独自のプロバイダーのJARは/opt/keycloak/providersに置き、必ずkc.sh buildより前にコピーします。公式イメージにはmicrodnfもdnfも入っていないため、RUN dnf installは通りません。RPMが要るときはガイドにあるubi-microを使った2段階ビルドに切り替え、ファイルを取るだけならRUN curlではなくADDを使います。FROMやCOPY --fromの書き方そのものはDockerfileの書き方と主要命令で確認できます。
Docker ComposeでKeycloakを本番モードで起動する定義
ここからは、前の章のDockerfileを使い、1台のホストでKeycloak・PostgreSQL・nginxの3つを動かす構成を組みます。インターネットに開けるのはnginxの443番だけで、KeycloakとPostgreSQLはComposeの内部ネットワークに閉じます。
compose.yamlの全体像と.envに逃がすパスワード3種
次のcompose.yamlは、Dockerfileと同じディレクトリに置く前提です。${...}の値は同じ場所の.envから読まれるので、DBのパスワードと一時管理者のパスワードはそちらに書き、リポジトリには含めません。
# compose.yaml
services:
postgres:
image: postgres:18
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: ${KC_DB_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak -d keycloak"]
interval: 10s
timeout: 5s
retries: 5
networks: [backend]
keycloak:
build: .
image: mykeycloak:26.8.1
command: ["start", "--optimized"]
environment:
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: ${KC_DB_PASSWORD}
KC_HOSTNAME: https://auth.example.com
KC_HTTP_ENABLED: "true"
KC_PROXY_HEADERS: xforwarded
KC_PROXY_TRUSTED_ADDRESSES: 172.28.0.0/24
KC_BOOTSTRAP_ADMIN_USERNAME: tmpadmin
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}
mem_limit: 2g
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "bash", "-c", "{ printf 'HEAD /health/ready HTTP/1.0\\r\\n\\r\\n' >&0; grep 'HTTP/1.0 200'; } 0<>/dev/tcp/localhost/9000"]
interval: 15s
timeout: 5s
retries: 5
start_period: 90s
networks: [backend]
nginx:
image: nginx:stable
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
keycloak:
condition: service_healthy
networks: [backend]
networks:
backend:
ipam:
config:
- subnet: 172.28.0.0/24
volumes:
pgdata:
Keycloakにはportsを書いていません。8080番も9000番もホストに出さず、nginxだけが内部ネットワーク経由で8080番へ転送します。depends_onのcondition: service_healthyは、Composeの起動順の制御にあるとおり、依存先のhealthcheckが通るまで次のコンテナを起動しない指定です。DBが応答する前にKeycloakが起動して接続エラーで落ちる、という順序の事故を防げます。nginx:stableのタグも、運用に入ったら版番号で固定してください。
KC_HOSTNAMEとKC_PROXY_HEADERSの不整合による403
プロキシでTLSを終端する構成は、リバースプロキシのガイドでedge terminationと呼ばれ、http-enabledでKeycloak側のHTTPを有効にする必要があります。設定の漏れと症状の対応は次のとおりです。
| 設定の漏れ | 起きること | 直し方 |
|---|---|---|
| KC_PROXY_HEADERS未設定 | オリジンを確かめる要求が403 | nginxならxforwardedを指定 |
| KC_HOSTNAMEが無いか誤り | リダイレクト先が内部名になる | https付きの公開URLを書く |
| KC_HTTP_ENABLED未設定 | プロキシから8080へ届かない | edge構成ではtrueにする |
| 信頼するプロキシの未指定 | 偽のX-Forwarded-Forを受け入れる | 信頼するプロキシのアドレス範囲 |
KC_HOSTNAMEはホスト名のガイドのとおり、ホスト名だけでもURL全体でも書けます。ホスト名だけだと、スキームとポートは要求から決まります。URL全体で書けば、プロキシのヘッダーに関係なくhttps://auth.example.comが使われるので、意図しないURLが出る余地がありません。KC_PROXY_TRUSTED_ADDRESSESを指定しないと全アドレスのヘッダーを信頼する既定になるため、上の例ではComposeのネットワークの範囲に限っています。ガイドは、IPアドレスは偽装できるので弱い保護にすぎないとも書いています。
nginxで/realms/だけ公開し/admin/を社内に限る設定
リバースプロキシのガイドは、公開してよいパスを表で示しています。/realms/・/resources/・/.well-known/は公開し、/admin/と/realms/master/は内部だけ、/metricsと/healthは公開しない、という区分けです。これをnginxで書くと次のようになります。
# nginx.conf(compose.yaml の nginx に default.conf として渡す)
server {
listen 443 ssl;
server_name auth.example.com;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port 443;
# 管理用は社内のアドレスからだけ通す
location /admin/ { allow 10.0.0.0/8; deny all; proxy_pass http://keycloak:8080; }
location /realms/master/ { allow 10.0.0.0/8; deny all; proxy_pass http://keycloak:8080; }
# アプリの利用者に必要なパス
location /realms/ { proxy_pass http://keycloak:8080; }
location /resources/ { proxy_pass http://keycloak:8080; }
location /.well-known/ { proxy_pass http://keycloak:8080; }
# それ以外は返さない
location / { return 404; }
}
nginxのlocationは前方一致で最も長いものが選ばれるため、/realms/master/の制限が/realms/より優先されます。10.0.0.0/8は社内ネットワークやVPNのアドレスに置き換えてください。管理コンソールを別のホスト名で出したい場合は、KC_HOSTNAME_ADMINで管理用のURLを分けられます。アプリ側でトークンを受け取ってからの検証手順はOIDCのIDトークンの検証手順にまとめています。
管理ポート9000のヘルスチェックとメトリクスをcurlなしのイメージで使う方法
Keycloak 26系では、ヘルスチェックとメトリクスはアプリ用の8080番とは別の管理ポートに出ます。ここを正しく使えるかどうかで、起動順の制御と障害の検知が決まります。
/health/readyをbashで叩くhealthcheckの書き方
管理インターフェースのガイドによると、ヘルスとメトリクスを有効にすると既定の9000番で管理インターフェースが開きます。エンドポイントは4つあります。
/health/ready:要求を処理できる状態か。ロードバランサーと起動順の判定に使う/health/live:プロセスが動いているか。失敗したら再起動の対象/health/started:起動が終わったか/health:全チェックの集約
ヘルスチェックのガイドは、コンテナイメージからcurlなどのパッケージが除かれていると明記し、代わりにbashの/dev/tcpでHEAD /health/readyを送る書き方を示しています。前の章のcompose.yamlにあるhealthcheckがそれです。この方法はHTTPしか話せないので、Keycloak自身にTLSを持たせた構成では管理ポートもHTTPSになり、使えません。edge構成ならKeycloakはHTTPで動くため、そのまま通ります。start_periodを90秒にしているのは、初回起動時にDBのスキーマを作る時間を見込むためです。
データベースの接続プールの状態を見るチェックは、metrics-enabledも有効なときだけ/health/readyに含まれます。Dockerfileで両方をtrueにしているのはこのためです。
9000番を外に出さずPrometheusとロードバランサーから見る構成
リバースプロキシのガイドは、9000番をプロキシ経由で公開しないよう求めています。ヘルスとメトリクスの情報を外に出さないためです。Prometheusで/metricsを集めるなら、Prometheusのコンテナを同じbackendネットワークに入れ、keycloak:9000を直接見に行かせます。
クラウドのロードバランサーを前に置く場合も、ヘルスチェックの宛先は9000番の/health/readyにし、インターネット側のリスナーとは分けます。本番構成のガイドは、DBの移行などで初期化中でもliveとstartedはUPを返すので、ロードバランサーに対してはreadyを見るようにという指示です。liveを見ていると、初期化が終わる前の要求を受けてしまいます。
メモリ上限・起動確認・トラブル時のhostname-debugで本番投入前に確かめる項目
定義がそろったら、メモリの割り当てと公開URLを確かめてから利用者に開放します。
コンテナのメモリ上限2GBとMaxRAMPercentage 70%のヒープ配分
コンテナのガイドによると、Keycloakのヒープは固定値ではなく、コンテナのメモリ量に対する割合で決まります。既定は最大ヒープが70%(-XX:MaxRAMPercentage=70)、初期ヒープが50%です。ガイドはメモリ上限を必ず設定するよう求め、小規模な本番構成の目安を2GBとしています。
compose.yamlのmem_limit: 2gはこの目安に合わせた値です。上限を書かないとホスト全体のメモリを基準にヒープが決まり、同じホストのPostgreSQLとメモリを奪い合います。割合を変えたいときは環境変数JAVA_OPTS_KC_HEAPで上書きします。
起動後に.well-knownとhostname-debugで公開URLを検証する手順
起動からURLの確認までは、次の順で行います。
# ビルドして起動し、keycloak が healthy になるのを待つ
docker compose up -d --build
docker compose ps
# 公開URLが KC_HOSTNAME どおりかを OIDC のメタデータで確かめる
curl -s https://auth.example.com/realms/myrealm/.well-known/openid-configuration \
| grep -o '"issuer":"[^"]*"'
# 起動ログでエラーを確かめる
docker compose logs keycloak --tail 50
issuerがhttps://auth.example.com/realms/myrealmになっていれば、ホスト名とプロキシの設定は正しい状態です。http://や内部名が出る場合は、環境変数にKC_HOSTNAME_DEBUG: "true"を足して再起動し、社内から/realms/master/hostname-debugを開きます。ホスト名のガイドにあるこのページは、Keycloakがどのヘッダーをどう解釈したかを一覧で表示します。確認が済んだら設定を外してください。
Docker Composeの単一ホスト構成を採用する条件と移行判断
ここまでの構成は、1台のホストで動くぶん、仕組みは単純です。そのぶん止まるときも1台ごと止まります。
1台のComposeで足りる規模と止められない認証基盤での見送り条件
1台のComposeを採用してよいのは、社内システムのSSOのように、更新や障害で数分から数十分ログインできなくても業務が続く用途です。Keycloakの更新では、系列をまたぐと全台を止める必要があり、1台構成ではそれがそのまま停止時間になります。
反対に、ECサイトや会員サービスのログインのように止まると売上に直結する用途では、1台のComposeは採用しません。本番構成のガイドも、障害時にログインを続けられるよう2台以上で動かすことを勧めています。本番モードの既定のキャッシュはispnで、ノードの発見にはDBを使うjdbc-pingが既定です。ホストの台数が増えるならKubernetesとOperatorへ移るのが自然な流れです。
更新とバックアップを回せない場合のRHBK・IDaaSへの切り替え
Docker化しても、2週間前後で出る修正版への追従とDBのバックアップは人の作業として残ります。2026年の修正版の頻度と更新の手順はKeycloakの脆弱性対応の手順で、実際の公開日とともに整理しました。26.8.1のリリースノートのように、1回の修正版に20件を超えるCVEが並ぶこともあります。
この周期でimageのタグを上げてビルドし直す運用を回せないなら、長期サポートのあるRed Hat build of Keycloakか、IDaaSを選ぶ段階です。Docker Composeで軽く動く別のOSSとしては、AuthentikやFusionAuthも比べられます。KeycloakのDocker構成の設計から、更新の自動化、IDaaSへの移行までを外部に任せたい場合は、一創の認証基盤・ID管理システム開発で支援しています。
KeycloakのDocker構成で導入担当者からよく受ける質問と回答
Docker・Docker ComposeでKeycloakを組むときに出やすい疑問をまとめました。
イメージのタグはlatestを指定してもよいですか?
本番では使わないでください。latestは取得した時点の版になり、どの版で動いているかが記録に残りません。系列をまたぐ更新が気づかないうちに起きると、DBのスキーマが書き換わり、元の版へ戻すにはバックアップからの復元が要ります。quay.io/keycloak/keycloak:26.8.1のように版番号で固定し、更新はタグの書き換えとビルドで行います。DockerfileのFROMは2か所あるので、両方を同じ版にそろえてください。
レルムの設定をコンテナの起動時に読み込めますか?
起動時のレルム設定の読み込みは可能です。エクスポートしたJSONを/opt/keycloak/data/importに置き、起動オプションには--import-realmの指定が必要です。ただしコンテナのガイドは、この方法は開発モードでこそ意味があると書いています。本番では、初回の構築時に1回だけ取り込み、以後の変更は管理コンソールや管理APIで行い、DBのバックアップで保全する運用が扱いやすくなります。
PostgreSQLも同じcompose.yamlに入れてよいですか?
社内向けの小規模な用途なら構いません。その場合は、名前付きボリュームの中身をpg_dumpで定期的にホストの外へ出すことが前提です。ホストが壊れると、Keycloakの全レルム・全ユーザーが一緒に失われるためです。クラウド上で動かすなら、DBはAmazon RDSなどのマネージドサービスに出し、KC_DB_URLをその接続先に変えるだけで移せます。接続プールとTLSの設定値はKeycloakのデータベース設定を参照してください。
Keycloak自体に証明書を持たせる構成とプロキシ終端はどちらがよいですか?
Docker Composeでnginxを前に置くなら、プロキシでTLSを終端する構成が扱いやすくなります。証明書の更新がnginxだけで済み、管理ポートのhealthcheckもHTTPのまま書けるためです。Keycloakに証明書を持たせるのは、プロキシとKeycloakの間の通信も暗号化しなければならない要件がある場合です。そのときは管理ポートもHTTPSになるので、本記事のbashによるhealthcheckは使えず、ロードバランサー側のチェックに頼ることになります。
docker compose upで複数台に増やせますか?
同じホスト内でKeycloakのコンテナを増やしても、ホストの障害には耐えられないので意味は薄いです。本番モードの既定ではDBを使うjdbc-pingでノード同士が見つかるため、複数ホストで同じDBを共有すればクラスタは組めます。複数ホストに分けるなら、ホストの管理とローリング更新をまとめて扱えるKubernetesのほうが向いています。
関連記事
- Keycloakとは?Oktaとの違いと連携手順|Auth0・Cognito比較で導入を判断【2026年10月】:Keycloakの機能と他製品との違いを確認できます。
- Keycloakのデータベース設定と使い方|PostgreSQL接続・対応DB・バックアップから権限モデルまで:DB接続とバックアップの設定値を詳しく扱っています。
- Keycloakの脆弱性対応の手順:2026年のCVEと修正版・更新判定・監視の実装:Docker構成での更新の手順と判定コマンドを押さえられます。
- 認証・ID管理とは?MFA・SSO・OIDC・IDaaSの違いと選定を解説【2026年版】:自前運用とIDaaSを比べる際の前提知識です。
- Dockerfileとは|書き方・ファイル名(拡張子)・主要命令とsyntaxの版を実測で解説【2026年10月】:2段階ビルドの書き方の基礎です。