Offre Durée limitée : -10% sur tout le site* avec le code ELYPSEWELCOME10

Installer Keycloak avec Docker sur un VPS Linux : un SSO pour toutes vos applications auto-hébergées

Mis à jour le 7 novembre 2026 19 min de lecture 15 sections

Keycloak : un SSO pour vos applications auto-hébergées

Dès que l'on héberge plus de deux ou trois services sur un VPS Linux, la gestion des comptes devient un problème en soi : un mot de passe pour Nextcloud, un autre pour Grafana, un troisième pour Portainer, chacun avec sa propre politique de double authentification. Keycloak règle ce problème en centralisant l'authentification. C'est un fournisseur d'identité open source, créé chez Red Hat, bâti sur Quarkus et hébergé par la CNCF (Cloud Native Computing Foundation) comme projet en incubation depuis avril 2023. Il parle les protocoles standard OpenID Connect (OIDC), OAuth 2.0 et SAML 2.0 : toute application compatible délègue sa page de connexion à Keycloak, qui gère les utilisateurs, les mots de passe, les rôles, les sessions et la 2FA par code OTP ou clé WebAuthn.

Concrètement, un utilisateur se connecte une seule fois (single sign-on, SSO) et accède ensuite à Nextcloud, Grafana, Portainer, Proxmox VE ou Jellyfin (via un plugin communautaire) sans ressaisir ses identifiants. Désactiver un compte dans Keycloak le coupe partout en même temps. Ce guide déploie Keycloak en mode production avec Docker Compose et PostgreSQL, derrière un reverse proxy nginx ou Traefik en HTTPS, puis crée un realm, un client OIDC et des utilisateurs, et branche Grafana comme première application. Il couvre aussi la mémoire de la JVM, la sauvegarde de la base et les erreurs classiques de hostname et de redirection.

Les commandes sont prévues pour Ubuntu 24.04 LTS ou Debian 13 et la branche Keycloak 26.8 (version 26.8.2 au moment de la rédaction).

Prérequis

  • Un VPS Linux avec au moins 4 Go de RAM : Keycloak seul réclame 2 Go pour un petit déploiement de production, et PostgreSQL, nginx et vos autres conteneurs ont besoin du reste ;
  • Docker Engine et Docker Compose v2 installés (installer Docker sur un VPS) ; pour la syntaxe des fichiers Compose, voir Docker Compose sur VPS Linux ;
  • Un sous-domaine dédié, par exemple sso.exemple.fr, avec un enregistrement DNS de type A vers l'adresse IP publique du VPS ;
  • Les ports 80 et 443 ouverts dans le pare-feu (ouvrir des ports avec UFW) ;
  • Un accès SSH par clé avec un utilisateur non root membre du groupe docker (sécuriser SSH sur VPS Linux).

Pourquoi pas start-dev : mode développement et mode production

La plupart des tutoriels lancent Keycloak avec la commande start-dev. C'est le mode développement : il accepte le HTTP en clair, stocke les données dans une base de fichiers dev-file embarquée et ne vérifie pas le hostname. La documentation officielle le déconseille explicitement pour un serveur exposé. Le mode start impose un hostname, une vraie base de données et une terminaison TLS, ce qui est exactement ce que l'on veut sur un VPS.

Réglagestart-devstart (production)
Base de données par défautdev-file (fichier local, données perdues si le conteneur est recréé sans volume)À fournir : PostgreSQL, MariaDB, MySQL, Oracle ou SQL Server
HostnameDéduit de chaque requête (hostname-strict à false)Obligatoire via KC_HOSTNAME, sinon le serveur refuse de démarrer
TransportHTTP sur le port 8080HTTPS sur 8443, ou HTTP sur 8080 si KC_HTTP_ENABLED=true derrière un reverse proxy
Cachelocalispn (Infinispan, prêt pour un cluster)
UsagePoste de développement, testsTout serveur accessible depuis Internet

Préparer le projet et les secrets

Créez un répertoire dédié et un fichier .env qui contiendra les secrets. Docker Compose lit ce fichier automatiquement pour remplacer les variables ${...} du fichier YAML, ce qui évite d'écrire les mots de passe en clair dans docker-compose.yml :

mkdir -p ~/keycloak && cd ~/keycloak
cat > .env <<EOF
DB_PASSWORD=$(openssl rand -base64 32 | tr -d '/+=')
KC_ADMIN_USER=bootstrap
KC_ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=')
EOF
chmod 600 .env && cat .env

Notez le mot de passe du compte bootstrap : il sert une seule fois, pour la première connexion à la console d'administration. Keycloak crée ce compte dans le realm master au premier démarrage uniquement, le marque comme temporaire et affiche une bannière tant qu'il existe. Vous le remplacerez par un administrateur permanent un peu plus loin.

Le fichier docker-compose.yml : Keycloak et PostgreSQL

La pile tient en deux services : la base de données PostgreSQL 17 et Keycloak lui-même, lancé avec start. Keycloak teste officiellement PostgreSQL 18 et prend en charge les versions 14 à 18.

cat > docker-compose.yml <<'EOF'
services:
  db:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_DB: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U keycloak -d keycloak"]
      interval: 10s
      timeout: 5s
      retries: 5

  keycloak:
    image: quay.io/keycloak/keycloak:26.8
    restart: unless-stopped
    command: start
    depends_on:
      db:
        condition: service_healthy
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://db:5432/keycloak
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: ${DB_PASSWORD}
      KC_HOSTNAME: https://sso.exemple.fr
      KC_HTTP_ENABLED: "true"
      KC_PROXY_HEADERS: xforwarded
      KC_HEALTH_ENABLED: "true"
      KC_METRICS_ENABLED: "true"
      KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_ADMIN_USER}
      KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}
    ports:
      - 127.0.0.1:8080:8080
    deploy:
      resources:
        limits:
          memory: 2G
    healthcheck:
      test:
        - CMD
        - bash
        - -c
        - >-
          { printf 'HEAD /health/ready HTTP/1.0\r\n\r\n' >&0;
          grep -q 'HTTP/1.0 200'; } 0<>/dev/tcp/localhost/9000
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 90s

volumes:
  pgdata:
EOF

Remplacez sso.exemple.fr par votre sous-domaine. Chaque variable KC_* correspond à une option de la ligne de commande kc.sh et joue un rôle précis :

VariableRôle
KC_DB, KC_DB_URL, KC_DB_USERNAME, KC_DB_PASSWORDConnexion JDBC à PostgreSQL. db est le nom du service Compose, résolu sur le réseau interne de la pile.
KC_HOSTNAMEURL publique de Keycloak. Avec le schéma https://, Keycloak fixe lui-même le protocole et le port dans toutes les URL qu'il génère (découverte OIDC, redirections, liens de réinitialisation) au lieu de les déduire de la requête.
KC_HTTP_ENABLEDAutorise l'écoute en HTTP sur le port 8080. Le chiffrement TLS est assuré par le reverse proxy, qui termine le HTTPS (mode edge).
KC_PROXY_HEADERSxforwarded fait lire à Keycloak les en-têtes X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host et X-Forwarded-Port envoyés par nginx ou Traefik. La valeur forwarded attend l'en-tête Forwarded de la RFC 7239. Sans cette option, les requêtes passées par le proxy qui vérifient leur origine reçoivent une erreur 403.
KC_PROXY_TRUSTED_ADDRESSES (optionnel)Liste d'adresses ou de plages CIDR dont les en-têtes X-Forwarded-* sont acceptés. Par défaut, tout est accepté. Avec nginx installé sur l'hôte, mettez la plage du réseau Docker de la pile (docker network inspect keycloak_default).
KC_HEALTH_ENABLED, KC_METRICS_ENABLEDActivent les endpoints /health/* et /metrics sur le port de management 9000, que l'on ne publie pas. Le healthcheck Compose utilise bash et /dev/tcp parce que l'image officielle ne contient pas curl.
KC_BOOTSTRAP_ADMIN_USERNAME, KC_BOOTSTRAP_ADMIN_PASSWORDCompte administrateur temporaire, créé au premier démarrage seulement. Les anciennes variables KEYCLOAK_ADMIN et KEYCLOAK_ADMIN_PASSWORD des tutoriels d'avant Keycloak 26 ne sont plus la méthode documentée.

Le port 8080 n'est exposé que sur 127.0.0.1 : seul le reverse proxy local peut joindre Keycloak. Le port 9000 n'est pas publié du tout. Si vous préférez Traefik dans un conteneur, retirez le bloc ports et ajoutez les labels présentés plus bas.

Reverse proxy nginx ou Traefik en HTTPS

Keycloak n'accepte pas un déploiement sans TLS, et derrière un proxy il a besoin de connaître le protocole et l'hôte vus par le navigateur. La documentation demande que le reverse proxy écrase les en-têtes X-Forwarded-* plutôt que de les compléter, pour qu'un client ne puisse pas injecter sa propre valeur. D'où $remote_addr plutôt que $proxy_add_x_forwarded_for dans la configuration nginx ci-dessous. Si nginx n'est pas encore installé, suivez d'abord nginx en reverse proxy sur VPS Linux.

sudo apt update && sudo apt install -y nginx certbot python3-certbot-nginx
sudo nano /etc/nginx/sites-available/keycloak.conf
server {
    listen 80;
    server_name sso.exemple.fr;

    proxy_set_header Host              $host;
    proxy_set_header X-Forwarded-For   $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host  $host;
    proxy_set_header X-Forwarded-Port  $server_port;

    # Console d'administration et realm master : uniquement depuis vos adresses
    location ~ ^/(admin|realms/master)/ {
        allow 203.0.113.42;      # votre IP fixe
        allow 100.64.0.0/10;     # plage Tailscale, si vous l'utilisez
        deny all;
        proxy_pass http://127.0.0.1:8080;
    }

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}
sudo ln -s /etc/nginx/sites-available/keycloak.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d sso.exemple.fr

Certbot ajoute le bloc listen 443 ssl, le certificat Let's Encrypt et la redirection HTTP vers HTTPS, puis renouvelle le certificat tout seul (Certbot et Let's Encrypt sur VPS Linux). La restriction sur /admin/ et /realms/master/ suit la recommandation officielle de ne pas exposer la console d'administration à tout Internet. Si vous n'avez pas d'IP fixe, passez par un réseau privé Tailscale entre votre poste et le VPS : faites résoudre sso.exemple.fr vers l'adresse Tailscale du serveur dans le fichier hosts de votre poste, et nginx verra arriver la console depuis la plage 100.64.0.0/10.

Un mot sur le chiffrement entre nginx et le conteneur : ici TLS s'arrête au proxy et Keycloak écoute en HTTP sur la boucle locale, ce que la documentation appelle le mode edge. Elle lui préfère le mode re-encrypt, où le proxy rechiffre vers Keycloak. Sur un VPS unique où ce trafic ne quitte jamais 127.0.0.1, le mode edge est le compromis habituel ; dès que le proxy et Keycloak tournent sur deux machines, configurez un certificat côté Keycloak (KC_HTTPS_CERTIFICATE_FILE et KC_HTTPS_CERTIFICATE_KEY_FILE) et retirez KC_HTTP_ENABLED.

Variante Traefik. Traefik renseigne de lui-même X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host et X-Forwarded-Port vers le conteneur cible, donc KC_PROXY_HEADERS=xforwarded reste valable. Dans le service keycloak, remplacez le bloc ports par le réseau partagé avec Traefik et ces labels :

    labels:
      - traefik.enable=true
      - traefik.http.routers.keycloak.rule=Host(`sso.exemple.fr`)
      - traefik.http.routers.keycloak.entrypoints=websecure
      - traefik.http.routers.keycloak.tls.certresolver=letsencrypt
      - traefik.http.services.keycloak.loadbalancer.server.port=8080

Le nom du certresolver et de l'entrypoint dépendent de votre configuration Traefik. Pour une vue d'ensemble des façons de publier un conteneur en HTTPS, voir publier un service en HTTPS sur un VPS Linux.

Démarrer Keycloak et créer l'administrateur permanent

docker compose up -d
docker compose logs -f keycloak

Sans image pré-construite, le premier démarrage exécute une phase de build interne puis applique les migrations de schéma sur PostgreSQL : comptez une à deux minutes. La ligne de log qui annonce started in puis Listening on: http://0.0.0.0:8080 indique que le serveur est prêt, et docker compose ps doit afficher healthy après le délai de grâce de 90 secondes du healthcheck.

Ouvrez https://sso.exemple.fr/admin/ et connectez-vous avec le compte bootstrap. La console affiche un avertissement : ce compte est temporaire. Créez tout de suite votre administrateur définitif dans le realm master :

  1. Users, puis Create new user : renseignez le nom d'utilisateur et l'e-mail, validez avec Create ;
  2. onglet Credentials, Set password, avec Temporary désactivé ;
  3. onglet Role mapping, Assign role, filtrez sur les rôles de realm et cochez admin ;
  4. déconnectez-vous, reconnectez-vous avec ce nouveau compte, puis supprimez l'utilisateur bootstrap. Vous pouvez aussi retirer les deux variables KC_BOOTSTRAP_* du fichier Compose : elles ne servent qu'au tout premier démarrage.

Activez immédiatement la double authentification sur ce compte depuis la console du compte, https://sso.exemple.fr/realms/master/account/, rubrique Signing in. Un administrateur Keycloak sans 2FA, c'est la clé de toutes vos applications derrière un seul mot de passe.

Créer un realm, des utilisateurs et imposer la 2FA

Un realm est un espace isolé : ses utilisateurs, ses rôles, ses clients et ses réglages de sécurité ne sont partagés avec aucun autre realm. Le realm master est réservé à l'administration de Keycloak. Vos applications et vos utilisateurs vont dans un realm dédié :

  1. Menu Manage realms, bouton Create realm, nom homelab, puis Create. Le realm créé devient le realm courant ;
  2. Realm roles, Create role : créez admin, editor et viewer. Ces trois rôles seront traduits en rôles Grafana plus loin ;
  3. Users, Create new user : nom d'utilisateur, e-mail, prénom, nom, Create, puis onglet Credentials pour le mot de passe et onglet Role mapping pour attribuer les rôles. Vous pouvez laisser Temporary activé : l'utilisateur devra changer son mot de passe à la première connexion.

Pour la double authentification, allez dans Authentication, onglet Required actions, et activez Set as default action sur la ligne Configure OTP. Tout nouvel utilisateur devra enregistrer une application TOTP (FreeOTP, Google Authenticator, Aegis ou tout autre client compatible) à sa première connexion. Pour les comptes déjà créés, ajoutez Configure OTP dans le champ Required user actions de leur fiche. L'onglet Policies permet de régler le type de code (TOTP ou HOTP), sa longueur et sa durée.

L'URL de découverte OpenID Connect du realm, à fournir aux applications qui savent se configurer seules, est https://sso.exemple.fr/realms/homelab/.well-known/openid-configuration. Ouvrez-la dans un navigateur : si les champs issuer, authorization_endpoint et token_endpoint commencent bien par https://sso.exemple.fr, le hostname et les en-têtes de proxy sont corrects.

Créer un client OIDC

Dans le vocabulaire Keycloak, un client est une application autorisée à demander l'authentification des utilisateurs du realm. Chaque application auto-hébergée a son propre client, avec son identifiant, son secret et la liste des URL de redirection autorisées. Exemple pour Grafana :

  1. Clients, Create client : type OpenID Connect, Client ID grafana, puis Next ;
  2. Étape Capability config : activez Client authentication (client confidentiel, avec secret) et laissez Standard flow coché, c'est le flux authorization code utilisé par les applications web ; Next ;
  3. Étape Login settings : Root URL https://grafana.exemple.fr, Valid redirect URIs https://grafana.exemple.fr/login/generic_oauth, Web origins https://grafana.exemple.fr, puis Save ;
  4. onglet Credentials : copiez le Client secret.

La liste Valid redirect URIs est le réglage le plus sensible : Keycloak refuse toute redirection vers une URL qui n'y figure pas, et c'est voulu. Évitez le joker * seul, qui autoriserait n'importe quel site à récupérer un code d'autorisation. Sous l'onglet Client scopes, le scope roles est assigné par défaut : il place les rôles de realm de l'utilisateur dans le jeton d'accès, sous le claim realm_access.roles. Le sous-onglet Evaluate permet de générer un jeton d'exemple pour un utilisateur et de vérifier les claims réellement envoyés.

Brancher une première application : Grafana

Grafana prend en charge n'importe quel fournisseur OIDC via sa section [auth.generic_oauth]. Chaque clé de grafana.ini se surcharge par une variable d'environnement de la forme GF_<SECTION>_<CLÉ>, les points de la section devenant des tirets bas. Si Grafana tourne déjà en conteneur, comme dans notre guide Grafana et Prometheus sur VPS Linux, ajoutez ces variables à son service Compose :

    environment:
      GF_SERVER_ROOT_URL: https://grafana.exemple.fr
      GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
      GF_AUTH_GENERIC_OAUTH_NAME: Keycloak
      GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: "true"
      GF_AUTH_GENERIC_OAUTH_CLIENT_ID: grafana
      GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: le-secret-copie-dans-keycloak
      GF_AUTH_GENERIC_OAUTH_SCOPES: openid email profile offline_access roles
      GF_AUTH_GENERIC_OAUTH_EMAIL_ATTRIBUTE_PATH: email
      GF_AUTH_GENERIC_OAUTH_LOGIN_ATTRIBUTE_PATH: preferred_username
      GF_AUTH_GENERIC_OAUTH_NAME_ATTRIBUTE_PATH: name
      GF_AUTH_GENERIC_OAUTH_AUTH_URL: https://sso.exemple.fr/realms/homelab/protocol/openid-connect/auth
      GF_AUTH_GENERIC_OAUTH_TOKEN_URL: https://sso.exemple.fr/realms/homelab/protocol/openid-connect/token
      GF_AUTH_GENERIC_OAUTH_API_URL: https://sso.exemple.fr/realms/homelab/protocol/openid-connect/userinfo
      GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: "contains(realm_access.roles[*], 'admin') && 'Admin' || contains(realm_access.roles[*], 'editor') && 'Editor' || 'Viewer'"

Après docker compose up -d, la page de connexion de Grafana propose un bouton Sign in with Keycloak. L'expression role_attribute_path est évaluée en JMESPath sur le jeton d'identité, puis la réponse userinfo, puis le jeton d'accès : un utilisateur porteur du rôle de realm admin devient administrateur Grafana, editor devient éditeur, et tous les autres sont lecteurs. GF_SERVER_ROOT_URL garantit que l'URL de retour /login/generic_oauth est construite avec le bon domaine derrière le reverse proxy.

Et Nextcloud ? Le principe est identique avec l'application OpenID Connect user backend (user_oidc), installable depuis le catalogue d'applications. Créez un client nextcloud dans Keycloak avec https://cloud.exemple.fr/* en URL de redirection, puis déclarez le fournisseur en une commande sur votre instance (voir installer Nextcloud avec Docker Compose) :

docker compose exec --user www-data app php occ user_oidc:provider keycloak \
  --clientid=nextcloud --clientsecret=le-secret \
  --discoveryuri=https://sso.exemple.fr/realms/homelab/.well-known/openid-configuration

Portainer (fournisseur OAuth personnalisé), Proxmox VE (realm de type OpenID Connect) et Jellyfin (plugin SSO communautaire) se branchent de la même façon : un client par application, l'URL de découverte du realm, et les rôles ou groupes Keycloak pour les droits.

Mémoire : dimensionner la JVM de Keycloak

Keycloak tourne dans une machine virtuelle Java, et la taille de son tas (heap) se calcule à partir de la mémoire du conteneur : par défaut, l'image fixe -XX:MaxRAMPercentage=70 (tas maximal à 70 % de la mémoire du conteneur) et -XX:InitialRAMPercentage=50 (tas initial à 50 %). D'où la règle de la documentation : toujours définir une limite mémoire sur le conteneur. Sans limite, la JVM considère toute la RAM du VPS comme sienne, peut grimper jusqu'à 70 % de celle-ci et ne la rend que lentement au système, au détriment de PostgreSQL et de vos autres services.

La limite de 2 Go du fichier Compose correspond à la recommandation officielle pour un petit déploiement de production. En dessous, la documentation indique un plancher de 750 Mo pour retrouver l'ancien plafond de tas de 512 Mo : c'est viable pour quelques utilisateurs, mais sans marge pour les pics d'activité. Pour ajuster finement, la variable JAVA_OPTS_KC_HEAP remplace les options de tas par défaut :

      JAVA_OPTS_KC_HEAP: "-XX:MaxRAMPercentage=65 -XX:MaxHeapFreeRatio=30"

Surveillez la consommation réelle avec docker stats keycloak-keycloak-1 et, sur le VPS lui-même, avec htop ou btop. Un conteneur qui disparaît avec le code de sortie 137 a été tué par le noyau faute de mémoire : augmentez la limite ou passez sur un VPS mieux doté plutôt que de rogner sur la JVM.

Sauvegarder Keycloak : la base PostgreSQL

Tout l'état de Keycloak vit dans PostgreSQL : realms, clients, secrets, utilisateurs, mots de passe hachés, secrets OTP, sessions hors ligne. Sauvegarder la base, c'est sauvegarder Keycloak. Un pg_dump au format personnalisé, compressé, lancé depuis le conteneur de base :

mkdir -p ~/backups/keycloak
docker compose -f ~/keycloak/docker-compose.yml exec -T db \
  pg_dump -U keycloak -Fc keycloak > ~/backups/keycloak/keycloak-$(date +%F).dump

Pour restaurer sur une base vide, par exemple sur un nouveau VPS après avoir relancé la pile :

docker compose exec -T db pg_restore -U keycloak -d keycloak --clean --if-exists \
  < ~/backups/keycloak/keycloak-2026-11-07.dump
docker compose restart keycloak

Planifiez la sauvegarde chaque nuit avec un timer systemd ou une tâche cron, puis copiez les fichiers hors du serveur (sauvegarder un VPS avec rsync). Ces dumps contiennent les secrets de tous vos clients OIDC : chiffrez-les avant de les envoyer hors site. En complément, Realm settings, menu Action, Partial export produit un fichier JSON de la configuration du realm (clients, rôles, groupes) sans les utilisateurs, pratique pour versionner ou rejouer la configuration sur une instance de test. Avant toute mise à jour de l'image Keycloak, faites un dump : les migrations de schéma sont automatiques mais pas réversibles.

Erreurs classiques de hostname et de redirection

Neuf problèmes sur dix avec Keycloak derrière un reverse proxy viennent du trio hostname, en-têtes de proxy et URL de redirection. La page de diagnostic intégrée aide à trancher : ajoutez KC_HOSTNAME_DEBUG: "true" au service, relancez, puis ouvrez https://sso.exemple.fr/realms/homelab/hostname-debug. Elle affiche les en-têtes reçus et les URL que Keycloak en déduit. Retirez l'option ensuite.

SymptômeCause probableCorrection
Keycloak s'arrête au démarrage en mode start en réclamant un hostnameKC_HOSTNAME absent : en production, hostname-strict vaut trueDéfinir KC_HOSTNAME avec l'URL publique complète
Erreur 403 sur la console d'administration ou sur une page de login passée par le proxyKC_PROXY_HEADERS absent, ou proxy qui n'envoie pas les X-Forwarded-*Ajouter KC_PROXY_HEADERS=xforwarded et vérifier les proxy_set_header nginx
Message HTTPS required sur la page de connexionKeycloak croit recevoir du HTTP en clair : X-Forwarded-Proto manquant ou non pris en compteMême correction que ci-dessus ; ne pas baisser le réglage Require SSL du realm
Liens générés en http://, avec le port 8080, ou vers un mauvais hôte ; boucle de redirectionKC_HOSTNAME réduit au nom d'hôte sans schéma, ou X-Forwarded-Host et X-Forwarded-Port absentsÉcrire KC_HOSTNAME=https://sso.exemple.fr avec le schéma, contrôler via hostname-debug
Invalid parameter: redirect_uri au moment de se connecter à une applicationL'URL de retour envoyée par l'application ne figure pas dans Valid redirect URIs du clientAjouter l'URL exacte (schéma, hôte, chemin) ; côté Grafana, vérifier GF_SERVER_ROOT_URL
Erreur Invalid client credentials ou unauthorized_clientSecret erroné, ou Client authentication désactivé alors que l'application envoie un secretRégénérer le secret dans l'onglet Credentials et le recopier
Configuration copiée d'un ancien tutoriel : KC_PROXY=edge, KEYCLOAK_ADMIN, PROXY_ADDRESS_FORWARDINGOptions d'anciennes versions : l'option proxy et le hostname v1 ont été retirés dans Keycloak 26Utiliser KC_PROXY_HEADERS, KC_HOSTNAME et KC_BOOTSTRAP_ADMIN_*
Le conteneur redémarre en boucle, code 137Limite mémoire trop basse pour la JVMRemonter la limite à 2 Go, vérifier la RAM libre du VPS

Mettre à jour Keycloak

Le tag 26.8 suit les correctifs de la branche : docker compose pull puis docker compose up -d appliquent la dernière version 26.8.x. Les versions correctives arrivent souvent et corrigent des failles sérieuses : la 26.8.1 du 13 octobre 2026 en comptait plus de quinze, dont un contournement de la 2FA obligatoire et une élévation de privilèges d'un administrateur délégué. Un fournisseur d'identité en retard d'un correctif expose toutes les applications qu'il protège. Avant de changer de version mineure (26.8 vers 26.9), lisez le guide de migration officiel et faites un dump de la base. Pensez aussi à nettoyer les anciennes images Docker après quelques mises à jour.

Conclusion

Avec deux services Compose, un sous-domaine et une dizaine de variables KC_*, vous disposez d'un fournisseur d'identité de niveau professionnel sur votre VPS Linux : SSO OpenID Connect pour toutes vos applications auto-hébergées, double authentification imposée au niveau du realm, rôles centralisés et une seule base PostgreSQL à sauvegarder. Les trois réglages à ne jamais improviser sont KC_HOSTNAME avec son schéma https://, KC_PROXY_HEADERS accordé aux en-têtes réellement envoyés par nginx ou Traefik, et la limite mémoire du conteneur. Si la pile grossit, un serveur dédié permet d'ajouter un second nœud Keycloak et une base PostgreSQL répliquée sans changer la configuration des applications.

FAQ

Keycloak peut-il tourner sur un VPS avec 2 Go de RAM ?

Difficilement en production. La documentation officielle recommande une limite mémoire de 2 Go pour le seul conteneur Keycloak dans un petit déploiement de production, et un plancher de 750 Mo pour retrouver l'ancien tas JVM de 512 Mo. Avec PostgreSQL, nginx et les applications que Keycloak protège, un VPS de 4 Go de RAM est le minimum confortable ; à 2 Go, limitez Keycloak à 1 Go via la limite du conteneur et JAVA_OPTS_KC_HEAP, et acceptez des temps de démarrage plus longs.

Quelle est la différence entre un realm et un client dans Keycloak ?

Un realm est un espace isolé qui contient ses propres utilisateurs, rôles, groupes et réglages de sécurité (politique de mots de passe, OTP obligatoire, durée des sessions). Un client est une application déclarée dans ce realm, autorisée à demander l'authentification de ses utilisateurs : il possède un identifiant, un secret s'il est confidentiel et une liste d'URL de redirection valides. En pratique, un realm pour vos services et un client par application (Grafana, Nextcloud, Portainer) suffisent.

Pourquoi Keycloak renvoie-t-il une erreur 403 ou « HTTPS required » derrière nginx ?

Parce qu'il ne voit pas les en-têtes du reverse proxy. Sans KC_PROXY_HEADERS=xforwarded, Keycloak ignore X-Forwarded-Proto et X-Forwarded-Host : il croit recevoir du HTTP en clair depuis l'adresse du proxy, refuse les requêtes qui vérifient leur origine (403) et exige le HTTPS. Vérifiez que nginx envoie X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host et X-Forwarded-Port, puis contrôlez le résultat avec la page hostname-debug du realm après avoir activé KC_HOSTNAME_DEBUG.

Faut-il chiffrer le trafic entre le reverse proxy et le conteneur Keycloak ?

La documentation Keycloak préfère le mode re-encrypt, où le proxy termine TLS puis rechiffre vers Keycloak. Sur un VPS unique, où nginx joint le conteneur sur 127.0.0.1 et où le trafic ne quitte jamais la machine, le mode edge avec KC_HTTP_ENABLED=true est le compromis courant. Dès que le proxy et Keycloak tournent sur deux hôtes différents, installez un certificat dans Keycloak avec KC_HTTPS_CERTIFICATE_FILE et KC_HTTPS_CERTIFICATE_KEY_FILE et désactivez l'écoute HTTP.

J'ai perdu l'accès administrateur à Keycloak, comment le récupérer ?

Les variables KC_BOOTSTRAP_ADMIN_USERNAME et KC_BOOTSTRAP_ADMIN_PASSWORD ne servent qu'au tout premier démarrage, quand le realm master n'existe pas encore : les remettre dans le fichier Compose ne change rien sur une installation existante. La documentation prévoit la commande dédiée bootstrap-admin user, à lancer avec tous les nœuds Keycloak arrêtés et les mêmes options de base de données que le serveur. Avec Docker Compose : docker compose stop keycloak, puis docker compose run --rm keycloak bootstrap-admin user, qui demande un nom et un mot de passe, puis docker compose start keycloak. Connectez-vous avec ce compte temporaire, rétablissez un administrateur permanent et supprimez-le.

Que se passe-t-il pour mes applications si Keycloak est en panne ?

Les sessions déjà ouvertes continuent de fonctionner jusqu'à l'expiration de leurs jetons, mais plus personne ne peut se connecter : Keycloak devient un point de défaillance unique. Gardez un compte local d'administration dans chaque application pour les cas d'urgence (Grafana conserve son compte admin, Nextcloud accepte la connexion classique avec ?direct=1 dans l'URL de login), surveillez l'endpoint /health/ready et, si la disponibilité est critique, prévoyez un second nœud Keycloak et une base PostgreSQL répliquée sur un serveur dédié.

Keycloak prend-il aussi en charge SAML pour les applications qui ne parlent pas OIDC ?

Oui. Keycloak implémente OpenID Connect, OAuth 2.0 et SAML 2.0. Lors de la création d'un client, le type « SAML » remplace « OpenID Connect » et le realm expose ses métadonnées SAML aux applications qui le demandent. OIDC reste à privilégier quand l'application le propose : il est plus simple à configurer, à déboguer et à sécuriser derrière un reverse proxy.

Comment sauvegarder Keycloak sans arrêter le service ?

Un pg_dump de la base PostgreSQL suffit et se fait à chaud : docker compose exec -T db pg_dump -U keycloak -Fc keycloak > keycloak-$(date +%F).dump. Ce fichier contient les realms, les clients et leurs secrets, les utilisateurs et leurs mots de passe hachés, et les secrets OTP ; chiffrez-le avant de l'envoyer hors site. L'export partiel du realm depuis la console (Realm settings, Action, Partial export) complète utilement la sauvegarde pour versionner la configuration, mais il n'inclut pas les utilisateurs.