Por qué desplegar Keycloak en su VPS
Donde algunos IdP buscan la simplicidad, Keycloak busca la exhaustividad: aislamiento multi-tenant mediante los realms, federación de directorios LDAP/Active Directory, brokering hacia proveedores externos (Google, GitHub, otro OIDC), theming completo de las páginas de login y fine-grained authorization. Para una agencia que gestiona varios clientes o para un sistema de información con exigencias de conformidad, ese nivel de control es decisivo. El autoalojamiento en VPS le evita los costos por usuario de las ofertas IdP gestionadas y mantiene la totalidad de la base de identidades bajo su jurisdicción, un punto crítico para datos sensibles que no desea confiar a un tercero.
Las ventajas de un Keycloak autoalojado
- Múltiples realms para aislar por completo varios clientes o entornos en una misma instancia.
- Soporte nativo y completo de OpenID Connect, OAuth2 y SAML 2.0.
- Federación LDAP / Active Directory para reutilizar un directorio existente sin migración.
- Identity brokering: conexión mediante Google, GitHub o cualquier IdP externo en unos clics.
- Páginas de login totalmente personalizables (temas, idiomas, branding por realm).
- Políticas de autenticación detalladas: MFA condicional, duración de sesión, restricciones por rol.
Requisitos previos para este despliegue
Keycloak se ejecuta sobre la JVM (Quarkus desde la v17+) y sigue siendo más exigente que un IdP ligero. Prevea un VPS con 2 vCPU y 4 GB de RAM como mínimo, idealmente 6 GB si espera carga o varios realms activos. Una base PostgreSQL externa es muy recomendable en producción (no use nunca la base H2 integrada más allá de las pruebas). Docker y Docker Compose, un dominio dedicado (sso.midominio.com) y un reverse proxy que gestione el SSL completan los requisitos, ya que Keycloak necesita saber que se sirve detrás de un proxy HTTPS.
Desplegar Keycloak con PostgreSQL
Definir Keycloak y PostgreSQL en Compose
En su
docker-compose.yml, declare el serviciopostgres(imagenpostgres:16) y el serviciokeycloak(imagenquay.io/keycloak/keycloak). Conecte Keycloak a la base medianteKC_DB=postgres,KC_DB_URL,KC_DB_USERNAMEyKC_DB_PASSWORD.Configurar el modo producción y el proxy
Arranque con el comando
start(y nostart-dev). IndiqueKC_HOSTNAME=sso.midominio.comyKC_PROXY_HEADERS=xforwardedpara que Keycloak genere URL correctas detrás del reverse proxy. Defina el administrador inicial medianteKC_BOOTSTRAP_ADMIN_USERNAME/KC_BOOTSTRAP_ADMIN_PASSWORD.Arrancar y finalizar el build
Ejecute
docker compose up -d. En el primer arranque, Keycloak realiza un build Quarkus optimizado y luego migra el esquema PostgreSQL. Sigadocker compose logs -f keycloakhasta el mensaje que indica que el servidor está escuchando.Poner en marcha el reverse proxy SSL
Enrute
sso.midominio.comhacia el puerto8080del contenedor Keycloak mediante Caddy, Traefik o Nginx, con un certificado Let's Encrypt. Asegúrese de transmitir las cabecerasX-Forwarded-*, ya que de lo contrario las redirecciones de login se romperán.Crear un realm y un cliente
Conéctese a la consola de administración, cree un realm dedicado (nunca el realm
masterpara sus aplicaciones) y luego un cliente OIDC. Ajuste elValid redirect URIsde su aplicación y recupere elClient IDy el secreto en la pestaña Credentials.Conectar una aplicación y probar el flujo
Configure su aplicación con la URL de descubrimiento
https://sso.midominio.com/realms/mi-realm/.well-known/openid-configuration. Cree un usuario de prueba en el realm, inicie un login y compruebe la emisión del token en las Sessions de la consola.
Imagen preoptimizada: separar el build del arranque
Por defecto, el comando start comprueba al arrancar si hace falta una fase de build de Quarkus y la ejecuta si es necesario: eso alarga el primer arranque y es lo que escribe en el árbol de la instalación. La documentación del fabricante recomienda lo contrario para un contenedor: ejecutar kc.sh build durante la construcción de la imagen y arrancar después con start --optimized. El parámetro --optimized indica a Keycloak que se ejecuta en una imagen ya optimizada y que puede omitir esa comprobación. Las opciones de build, como el tipo de base de datos (db) o la activación de las sondas (health-enabled), quedan fijadas en la imagen: si se repiten al arrancar con el mismo valor, se ignoran; con un valor distinto, provocan un error y exigen un nuevo build. Los secretos, contraseña de la base incluida, pertenecen a las opciones de configuración y se siguen suministrando en tiempo de ejecución.
Construir y ejecutar una imagen preoptimizada
Escribir un Dockerfile en dos etapas
La primera etapa parte de
quay.io/keycloak/keycloakcon el nombrebuilder, defineENV KC_DB=postgresyENV KC_HEALTH_ENABLED=truey ejecutaRUN /opt/keycloak/bin/kc.sh build. Fije un número de versión concreto en lugar delatest, para que cada reconstrucción sea reproducible.Copiar el resultado a la imagen final
La segunda etapa parte de la misma imagen y ejecuta
COPY --from=builder /opt/keycloak/ /opt/keycloak/. Coloque sus temas y proveedores personalizados antes del build: así los tiene en cuenta la optimización. Si añade archivos conCOPY, añada--chown=keycloak:keycloakpara que Keycloak pueda escribir en las carpetas afectadas.Arrancar con la opción optimizada
En Compose, sustituya el comando por
start --optimized. Detrás de un reverse proxy que termina el TLS, añadaKC_HTTP_ENABLED=true. Las variablesKC_HOSTNAMEyKC_PROXY_HEADERSy los accesos a la base siguen siendo configuración de ejecución.Conectar las sondas de salud
Con
KC_HEALTH_ENABLED=truedefinido en el build, los puntos/health/started,/health/livey/health/readyse sirven en el puerto de gestión9000, distinto del8080de la aplicación. No publique este puerto en Internet: úselo solo para elhealthcheckde Compose o su monitorización.
Keycloak o Authentik: ¿cuál elegir?
Desplace la tabla
| Criterio | Keycloak | Authentik |
|---|---|---|
| Caso de uso objetivo | SSO empresarial, multi-tenant, conformidad | Self-hosting, homelab, agencias |
| Protocolos | OIDC, OAuth2, SAML, LDAP | OIDC, OAuth2, SAML, LDAP, forward auth |
| Forward auth (proxy) | No nativo (mediante extensiones) | Nativo y central en la herramienta |
| Huella de recursos | Elevada (JVM, 4 GB+ de RAM) | Moderada (2-4 GB de RAM) |
| Multi-realm / tenants | Excelente (realms aislados) | Tenants soportados, menos avanzados |
| Personalización de los flujos | Temas y SPI Java | Flujos visuales por etapas |
| Curva de aprendizaje | Pronunciada, muy completa | Más accesible |
| Federación de directorios | Madura (LDAP/AD) | Buena (LDAP) |
Copias de seguridad y migración sin perder un realm
El estado de Keycloak reside en dos sitios: la base PostgreSQL y sus archivos de configuración (temas, proveedores, archivos de importación). La copia de referencia es un pg_dump programado, copiado fuera del VPS; pruebe la restauración en una instancia desechable, porque una copia que nunca se ha restaurado sigue siendo una hipótesis. La exportación de realms completa este dispositivo sin sustituirlo: kc.sh export --dir <carpeta>, o --realm mi-realm para un solo realm, con la opción --users para elegir la estrategia de exportación de usuarios. La documentación precisa que el servidor no debe estar arrancado durante la exportación, que la coherencia solo está garantizada con todos los nodos detenidos y que los eventos, las sesiones persistentes y los tokens revocados no se exportan. A partir de 50 000 usuarios, exporte a un directorio y no a un único archivo. En la importación, start --import-realm lee los archivos .json de la carpeta /opt/keycloak/data/import e ignora un realm que ya existe.
Lista de comprobación de operación
- Versión fijada — fije el número de versión de la imagen, lea las notas de versión antes de cambiar de rama mayor y reconstruya la imagen optimizada en cada actualización.
- Base con copia —
pg_dumpprogramado, copia fuera del VPS, restauración probada en una instancia desechable. - Memoria acotada — fije siempre un límite de memoria al contenedor: la JVM calcula su heap a partir de él, con un 70 % como máximo y un 50 % inicial por defecto.
- Sondas vigiladas — siga
/health/readyen el puerto9000, no publicado, desde su monitorización. - Cabeceras del proxy controladas — el reverse proxy debe sobrescribir las cabeceras
X-Forwarded-*recibidas del cliente, no añadirse a ellas, y no debe eludirse nunca. - Eventos activados — registre los inicios de sesión y las acciones de administración en cada realm, para saber quién se conectó y quién modificó qué.
Solución de problemas: el arranque falla con un sistema de archivos de solo lectura
Endurecer un contenedor suele implicar read_only: true en Compose o readOnlyRootFilesystem: true en Kubernetes. Con Keycloak, el tema está abierto desde abril de 2022 en la issue keycloak/keycloak n.º 11286 ("Keycloak does not work with Docker read_only: true") y seguía activa a finales de octubre de 2026. Lo que está establecido por parte del proyecto: un colaborador de Keycloak reprodujo el fallo en la versión 19.0.2 en septiembre de 2022, la issue está clasificada como mejora con la etiqueta "help wanted" y se añadió a un tablero de proyecto del repositorio en septiembre de 2026. Lo que no: la documentación oficial no describe a día de hoy ningún modo de solo lectura (la página dedicada a los contenedores no lo menciona) y ningún mantenedor ha validado una solución alternativa. Las soluciones siguientes proceden de participantes en la discusión; les funcionaron a ellos, en sus versiones, sin garantía tras una actualización. El 26 de octubre de 2026, un colaborador se ofreció a escribir la documentación que falta tras verificar él mismo estas soluciones.
Mensajes de error que conviene reconocer
sed: couldn't open temporary file /opt/jboss/keycloak/bin/seduHoQM0: Read-only file system— mensaje del informe inicial, sobre la antigua imagen WildFly (versión 16.1.1 en la issue): unsed -idel script de arranque no puede crear su archivo temporal. En la distribución Quarkus los síntomas son distintos, véanse las líneas siguientes.KC-SERVICES0075: Failed to get theme request: java.lang.RuntimeException: Temporary directory /opt/keycloak/bin/../data/tmp does not exist and it was not possible to create it.— notificado al actualizar a la 20.0.1: el servidor arranca y luego falla en la primera página que sirve un tema. Un participante indicó que un volumen escribible montado en/opt/keycloak/data/tmpresuelve este caso.- Arranque lento o fallo de escritura en
/opt/keycloak/lib/quarkus— un participante comparó el contenedor antes y después del arranque condocker diff: cambian tres carpetas,/tmp,/opt/keycloak/datay/opt/keycloak/lib/quarkus. La última contiene el resultado del build, questartregenera salvo que la imagen esté preoptimizada. - Carpeta
datade solo lectura tras unCOPY— un participante señala que olvidar--chown=keycloak:keycloakal copiar un archivo de realm deja/opt/keycloak/dataen manos de root y, por tanto, sin escritura para Keycloak. - Copia de
/opt/keycloaka un volumen al arrancar — solución con contenedor de inicialización, notificada en Kubernetes: funciona, pero varios participantes temen tener que volver a probarla en cada actualización.
Solución notificada en Docker Compose
Partir de la imagen preoptimizada
Reutilice la imagen construida más arriba.
kc.sh buildse ejecuta durante la construcción:/opt/keycloak/lib/quarkusya no se reescribe al arrancar, que se hace constart --optimized.Declarar el sistema de archivos de solo lectura
Añada
read_only: trueal serviciokeycloakdel archivo Compose. Sin ningún otro cambio, el contenedor falla: es el comportamiento que describe la issue.Suministrar los directorios escribibles
Monte un
tmpfsen/tmpy un volumen temporal en/opt/keycloak/data. En el informe que se apoya en una imagen preoptimizada, esos dos directorios bastaron; con una imagen no optimizada, otros participantes añadieron/opt/keycloak/lib/quarkus.Reponer lo que había en data
Un volumen temporal arranca vacío: lo que la imagen colocaba en esa carpeta, incluido
data/import, deja de verse allí. Si importa realms con--import-realm, monte su carpeta por separado, en solo lectura.Comprobar abriendo una página de login
Ejecute
docker compose up -dy luegodocker compose logs -f keycloak, y abra después la página de inicio de sesión: la primera petición de tema es la que hizo fallar algunos montajes. Termine condocker diffpara listar lo que el contenedor ha escrito realmente.
Solo lectura: un endurecimiento que el fabricante no documenta
Reserve este modo para los entornos donde una política lo exige, como una auditoría de seguridad o una regla del clúster, y acepte el coste: una configuración no documentada, que hay que volver a probar en cada actualización, algo que temen varios participantes de la issue. En un VPS único, otras medidas dan una ganancia más clara con menos mantenimiento: capacidades de Linux retiradas (cap_drop: [ALL]), opción no-new-privileges, puertos de gestión sin publicar y base PostgreSQL en una red Docker interna.
En producción, no sirva nunca Keycloak con la base H2 integrada ni exponga el realm master al público: cree un realm dedicado por aplicación o por cliente y reserve master para la administración. Para endurecer la instancia, desactive el registro libre, active el brute force detection en Realm Settings > Security Defenses y aprovisione todo mediante ficheros de importación de realm (--import-realm), de modo que versione su configuración en lugar de hacer clic en la interfaz.