Keycloak в Docker Compose: готовый файл
Если у вас три-пять внутренних сервисов и в каждом свой логин-пароль, рано или поздно кто-то забудет отключить доступ уволенному сотруднику в одном из них. Keycloak закрывает это одним центральным входом: SSO, OAuth2/OIDC, SAML, группы и роли — из коробки, без написания кода. Ниже — рабочий docker-compose.yml, с которым Keycloak поднимается на VPS за один прогон, плюс нюансы, которые обычно всплывают уже после того, как всё вроде бы заработало.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что даёт Keycloak и когда он оправдан
Keycloak — identity-провайдер от Red Hat (проект Kubernetes-нативный, но прекрасно живёт и в обычном Docker Compose). Он берёт на себя аутентификацию и авторизацию для остальных ваших сервисов: пользователь логинится один раз в Keycloak, а дальше получает токены, по которым его пускают в Grafana, Nextcloud, GitLab, внутренние API и что угодно ещё, поддерживающее OIDC или SAML.
Ставить его имеет смысл, когда у вас:
- больше двух-трёх сервисов с раздельным входом и хочется единой точки управления доступом;
- требование по комплаенсу (SOC2, ISO) вести централизованный аудит входов;
- нужны ролевые модели с группами, а не просто «есть аккаунт — есть доступ»;
- команда, где люди приходят и уходят, и вручную гонять доступы по десяти панелькам — уже боль.
Если сервис у вас один и пользователей десять, Keycloak, скорее всего, избыточен — это тяжёлый Java-процесс, ему нужна отдельная база и от 512 МБ – 1 ГБ RAM только под сам сервис. Для сравнения с более лёгкими альтернативами (Authelia, Authentik) стоит смотреть отдельно, здесь только про сам Keycloak.
Готовый docker-compose.yml для продакшена
Ниже связка Keycloak + PostgreSQL с healthcheck-ами и без открытого наружу порта БД. Файл рассчитан на то, что перед Keycloak будет reverse proxy (см. раздел про HTTPS ниже), поэтому сам Keycloak слушает только во внутренней docker-сети.
version: "3.8"
services:
keycloak-db:
image: postgres:16-alpine
container_name: keycloak-db
restart: unless-stopped
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: ${KC_DB_PASSWORD}
volumes:
- keycloak_db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak"]
interval: 10s
timeout: 5s
retries: 5
networks:
- keycloak_net
keycloak:
image: quay.io/keycloak/keycloak:26.0
container_name: keycloak
restart: unless-stopped
command: ["start", "--optimized"]
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://keycloak-db:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: ${KC_DB_PASSWORD}
KC_HOSTNAME: ${KC_HOSTNAME}
KC_HOSTNAME_STRICT: "true"
KC_HTTP_ENABLED: "true"
KC_PROXY_HEADERS: xforwarded
KC_HEALTH_ENABLED: "true"
KC_METRICS_ENABLED: "true"
KEYCLOAK_ADMIN: ${KC_ADMIN_USER}
KEYCLOAK_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}
depends_on:
keycloak-db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/9000 && echo -e 'GET /health/ready HTTP/1.1\\r\\nhost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && grep -q '\"status\": \"UP\"' <&3"]
interval: 15s
timeout: 5s
retries: 10
start_period: 60s
labels:
- "traefik.enable=true"
- "traefik.http.routers.keycloak.rule=Host(`${KC_HOSTNAME}`)"
- "traefik.http.routers.keycloak.entrypoints=websecure"
- "traefik.http.routers.keycloak.tls.certresolver=letsencrypt"
- "traefik.http.services.keycloak.loadbalancer.server.port=8080"
networks:
- keycloak_net
- proxy_net
networks:
keycloak_net:
driver: bridge
proxy_net:
external: true
volumes:
keycloak_db_data:
Обратите внимание на команду start --optimized — это продакшн-режим сборки образа (сборка кеша при старте пропускается), в отличие от start-dev, который годится только для локальных экспериментов и включает небезопасные дефолты (например, HTTP без строгой проверки хоста).
Версию образа фиксируйте явно, а не берите :latest — мажорные релизы Keycloak иногда меняют формат конфигурации, и внезапное обновление между рестартами контейнера ломает поднявшийся до этого инстанс. На момент подготовки этого материала актуальная стабильная линейка — 26.x, но перед разворачиванием сверьтесь с тегами на quay.io/keycloak/keycloak — Keycloak обновляется активно.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПеременные окружения и первый запуск
Создайте .env рядом с docker-compose.yml:
KC_DB_PASSWORD=замените_на_длинный_случайный_пароль
KC_HOSTNAME=auth.example.com
KC_ADMIN_USER=admin
KC_ADMIN_PASSWORD=замените_на_длинный_случайный_пароль
Сгенерировать пароли можно так:
openssl rand -base64 24
Дальше — сеть для reverse proxy (если её ещё нет) и запуск:
docker network create proxy_net
docker compose up -d
docker compose logs -f keycloak
Первый старт занимает от 30 секунд до пары минут — Keycloak применяет миграции схемы БД и прогревает JVM. Дождитесь в логах строки вида Keycloak … started in … Listening on: http://0.0.0.0:8080 — до этого healthcheck будет показывать unhealthy, это нормально на старте (для того и стоит start_period: 60s).
Проверить, что всё поднялось, изнутри контейнера:
docker exec -it keycloak curl -s http://127.0.0.1:9000/health/ready
Должны увидеть JSON со "status": "UP".
HTTPS через reverse proxy: Traefik или Caddy
Открывать Keycloak напрямую в интернет без TLS-терминации на входе — плохая идея: логин-форма и токены должны ходить только по HTTPS. В примере выше уже стоят лейблы для Traefik — если он у вас развёрнут по стандартной схеме, Keycloak подхватится автоматически, останется только направить DNS-запись auth.example.com на IP сервера. Подробно про сам Traefik как reverse proxy для докер-контейнеров — в отдельной статье: Traefik как reverse proxy для Docker.
Если вместо Traefik у вас Caddy, конфиг ещё короче — добавьте блок в Caddyfile:
auth.example.com {
reverse_proxy keycloak:8080
}
Caddy сам выпустит и обновит сертификат Let's Encrypt. Если предпочитаете разбираться с сертификатами вручную через certbot — этот путь тоже описан отдельно: установка Let's Encrypt SSL на VPS.
Важный момент, который часто ловят на проде: если Keycloak видит себя за прокси не как HTTPS, а как обычный HTTP (когда забыли выставить заголовки X-Forwarded-* на самом proxy или KC_PROXY_HEADERS в контейнере), редиректы после логина начинают вести на http://, браузер их блокирует смешанным контентом, и форма входа зацикливается. Проверяйте оба конца: и что Traefik/Caddy шлёт X-Forwarded-Proto: https, и что KC_PROXY_HEADERS=xforwarded стоит в переменных Keycloak.
Настройка realm, клиента и первого пользователя
По умолчанию Keycloak поднимается с realm master, предназначенным только для администрирования самого Keycloak — заводить туда рабочих пользователей не стоит. Создайте отдельный realm под ваши сервисы:
- Зайдите на
https://auth.example.com/admin/под учёткой изKEYCLOAK_ADMIN/KEYCLOAK_ADMIN_PASSWORD. - В выпадающем списке realm-ов слева — «Create realm», назовите, например,
company. - В
Clients→ «Create client» заведите клиента для вашего сервиса: Client ID — по имени приложения, Client authentication — включить (для confidential-клиентов, у которых есть свой бэкенд), Standard flow — включить. - Во вкладке
Credentialsклиента скопируйте Client secret — он понадобится приложению для обмена кода на токен. - В
Valid redirect URIsукажите точный адрес обратного вызова вашего приложения (например,https://app.example.com/auth/callback) — вписывать*в проде не стоит, это открывает дыру для redirect-атак.
Для теста заведите пользователя в Users → «Add user», задайте пароль во вкладке Credentials и снимите галочку Temporary, если не хотите, чтобы он менялся при первом входе.
Дальше в приложении, которое должно ходить через Keycloak, укажите стандартные OIDC-эндпоинты — их видно в Realm settings → General → Endpoints → OpenID Endpoint Configuration. Обычно это что-то вроде:
https://auth.example.com/realms/company/.well-known/openid-configuration
Большинство современных фреймворков и SSO-плагинов (Grafana, Nextcloud, GitLab) принимают этот URL напрямую и сами вытягивают все нужные адреса — issuer, authorization endpoint, token endpoint, jwks.
Бэкап, обновление и мониторинг
Вся ценная информация Keycloak — в PostgreSQL, поэтому бэкапить нужно именно базу, а не только volume контейнера самого Keycloak.
Бэкап дампом:
docker exec keycloak-db pg_dump -U keycloak keycloak | gzip > keycloak_$(date +%F).sql.gz
Восстановление:
gunzip -c keycloak_2026-08-20.sql.gz | docker exec -i keycloak-db psql -U keycloak keycloak
Для регулярных бэкапов проще завести отдельный контейнер вроде borgbackup или простой cron-скрипт на хосте, который складывает дампы куда-то за пределы этого же сервера (S3-совместимое хранилище, второй сервер). Если у вас уже есть общая схема бэкапов для докер-стека — подойдёт та же, что и для остальных сервисов.
Обновление между минорными версиями обычно проходит без сюрпризов:
docker compose pull keycloak
docker compose up -d keycloak
Мажорные обновления (например, между линейками 25.x и 26.x) стоит сначала прогонять на копии с тестовыми данными — Keycloak в release notes честно предупреждает о breaking changes в конфигурации и иногда в формате хранения токенов. Не пропускайте чейнджлог.
Для мониторинга включённый в конфиге выше KC_METRICS_ENABLED=true отдаёт Prometheus-метрики на /metrics (порт 9000 внутри контейнера) — количество активных сессий, время ответа, ошибки логина. Если у вас уже стоит Prometheus + Grafana, добавить туда Keycloak как ещё один target — минут пять работы.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько ресурсов нужно Keycloak на небольшую нагрузку?
Для 10-50 активных пользователей и пары клиентов хватает 1 vCPU и 1–2 ГБ RAM на сам Keycloak плюс отдельно ресурсы под PostgreSQL (обычно достаточно ещё 512 МБ – 1 ГБ). Под нагрузку от сотен одновременных логинов лучше закладывать больше и тестировать на реальном профиле трафика — точные цифры сильно зависят от количества realm-ов, клиентов и частоты обновления токенов.
Можно ли использовать SQLite вместо PostgreSQL?
Формально Keycloak поддерживает несколько СУБД (PostgreSQL, MySQL/MariaDB, Oracle, MS SQL), но SQLite среди официально поддерживаемых баз для продакшена не значится — для рабочего инстанса используйте PostgreSQL, это самый обкатанный вариант.
Что делать, если забыли админский пароль?
Переменные KEYCLOAK_ADMIN/KEYCLOAK_ADMIN_PASSWORD работают только при самом первом старте (создании учётки в пустой базе); дальше сменить пароль можно либо через веб-интерфейс под другой админской учёткой, либо через kc.sh с флагом добавления нового администратора внутри контейнера — почитайте документацию под вашу конкретную версию, синтаксис между релизами слегка менялся.
Нужен ли Keycloak, если у меня уже есть Authelia или Authentik?
Нет смысла ставить оба сразу — это решают одну и ту же задачу. Keycloak тяжелее, но даёт больше «энтерпрайзных» возможностей из коробки (SAML, тонкие ролевые модели, federation с внешними identity-провайдерами). Если хватает простого forward-auth перед несколькими сервисами — более лёгкие альтернативы могут быть удобнее.
Как защитить админку Keycloak от перебора паролей?
Кроме сильного пароля и HTTPS, включите в realm master политику брутфорс-защиты (Realm settings → Security defenses → Brute force detection) — она временно блокирует аккаунт после нескольких неудачных попыток входа. Дополнительно можно поставить fail2ban перед reverse proxy — как это настроить, описано в статье про fail2ban на VPS.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →