services: keycloak: build: context: . dockerfile: Dockerfile image: han-chat/keycloak:26.1.4-otp-1.0.0 command: ["start", "--optimized", "--import-realm"] environment: HAN_SECRET_VARS: >- KC_DB_PASSWORD KC_BOOTSTRAP_ADMIN_PASSWORD KEYCLOAK_OTP_MOCK_CODE KEYCLOAK_YANDEX_CAPTCHA_SERVER_KEY KEYCLOAK_OTP_HMAC_KEY KEYCLOAK_SETTINGS_BRIDGE_TOKEN KEYCLOAK_SMS_SERVICE_TOKEN KC_DB_PASSWORD_FILE: /run/secrets/keycloak_db_password KC_BOOTSTRAP_ADMIN_PASSWORD_FILE: /run/secrets/keycloak_admin_password KEYCLOAK_OTP_MOCK_CODE_FILE: /run/secrets/keycloak_otp_mock_code KEYCLOAK_YANDEX_CAPTCHA_SERVER_KEY_FILE: /run/secrets/keycloak_yandex_captcha_server_key KEYCLOAK_OTP_HMAC_KEY_FILE: /run/secrets/keycloak_otp_hmac_key KEYCLOAK_SETTINGS_BRIDGE_TOKEN_FILE: /run/secrets/keycloak_settings_bridge_token KEYCLOAK_SMS_SERVICE_TOKEN_FILE: /run/secrets/keycloak_sms_service_token KC_DB: postgres KC_DB_URL: ${KEYCLOAK_DB_URL:?KEYCLOAK_DB_URL is required} KC_DB_USERNAME: ${KEYCLOAK_DB_USERNAME:?KEYCLOAK_DB_USERNAME is required} KC_DB_URL_PROPERTIES: ${KC_DB_URL_PROPERTIES:-currentSchema=keycloak} KC_HOSTNAME: ${KEYCLOAK_PUBLIC_URL:?KEYCLOAK_PUBLIC_URL is required} PUBLIC_WEB_URL: ${PUBLIC_WEB_URL:?PUBLIC_WEB_URL is required for realm import} KC_HOSTNAME_STRICT: "true" KC_HTTP_ENABLED: "true" KC_HTTP_PORT: "8080" KC_HTTP_RELATIVE_PATH: /auth KC_PROXY_HEADERS: xforwarded KC_HEALTH_ENABLED: "true" KC_METRICS_ENABLED: "true" KC_HTTP_MANAGEMENT_PORT: "9000" KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_BOOTSTRAP_ADMIN_USERNAME:?bootstrap admin username is required} KEYCLOAK_OTP_MOCK_ENABLED: ${KEYCLOAK_OTP_MOCK_ENABLED:-true} KEYCLOAK_YANDEX_CAPTCHA_ENABLED: ${KEYCLOAK_YANDEX_CAPTCHA_ENABLED:-false} KEYCLOAK_YANDEX_CAPTCHA_CLIENT_KEY: ${KEYCLOAK_YANDEX_CAPTCHA_CLIENT_KEY:-} KEYCLOAK_OTP_SETTINGS_MAX_STALE_SEC: ${KEYCLOAK_OTP_SETTINGS_MAX_STALE_SEC:-300} KEYCLOAK_SETTINGS_BRIDGE_URL: ${KEYCLOAK_SETTINGS_BRIDGE_URL:-http://api-backend:8000/internal/settings/v1/otp} KEYCLOAK_SMS_SERVICE_URL: ${KEYCLOAK_SMS_SERVICE_URL:-http://sms-service:8080} KC_LOG_CONSOLE_OUTPUT: json KC_LOG_LEVEL: ${KEYCLOAK_LOG_LEVEL:-INFO} JAVA_OPTS_APPEND: ${KEYCLOAK_JAVA_OPTS:--XX:MaxRAMPercentage=70 -XX:InitialRAMPercentage=35} secrets: - keycloak_db_password - keycloak_admin_password - keycloak_otp_mock_code - keycloak_yandex_captcha_server_key - keycloak_otp_hmac_key - keycloak_settings_bridge_token - keycloak_sms_service_token expose: - "8080" - "9000" networks: - public - backend - observability - egress healthcheck: test: ["CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/9000 && printf 'GET /auth/health/ready HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && grep -q '200 OK' <&3"] interval: 15s timeout: 5s retries: 12 start_period: 60s read_only: true tmpfs: - /tmp:size=64m,mode=1770 - /opt/keycloak/data/tmp:size=64m,uid=1000,gid=0,mode=0770 security_opt: - no-new-privileges:true cap_drop: - ALL ulimits: core: {soft: 0, hard: 0} stop_grace_period: 30s restart: unless-stopped networks: public: backend: observability: egress: secrets: keycloak_db_password: file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/KEYCLOAK_DB_PASSWORD keycloak_admin_password: file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/KEYCLOAK_ADMIN_PASSWORD keycloak_otp_mock_code: file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/KEYCLOAK_OTP_MOCK_CODE keycloak_yandex_captcha_server_key: file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/KEYCLOAK_YANDEX_CAPTCHA_SERVER_KEY keycloak_otp_hmac_key: file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/KEYCLOAK_OTP_HMAC_KEY keycloak_settings_bridge_token: file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/KEYCLOAK_SETTINGS_BRIDGE_TOKEN keycloak_sms_service_token: file: ${HAN_SECRETS_DIR:-/run/han-chat/secrets}/KEYCLOAK_SMS_SERVICE_TOKEN