Ce guide suit la documentation de GitLab, relue le 15 octobre 2026 : utiliser des clés SSH avec GitLab CI/CD, les variables CI/CD, les clés de déploiement et la référence du fichier .gitlab-ci.yml. L'exemple déploie une application Docker Compose clonée sur le serveur dans ~/app. La même logique avec GitHub est décrite dans Déployer sur son VPS avec GitHub Actions.
Deux clés, deux rôles
- La clé du job permet à GitLab d'ouvrir une session SSH sur votre serveur. Sa partie privée vit dans une variable du projet, sa partie publique dans
~/.ssh/authorized_keysdu serveur. - La clé de déploiement permet au serveur de lire le dépôt pour
git pull. Sa partie privée reste sur le serveur, sa partie publique est déclarée dans le projet GitLab.
Les séparer limite les dégâts d'une fuite : la clé du job n'ouvre pas le dépôt, la clé du serveur n'ouvre pas le serveur.
1. Donner au serveur l'accès au dépôt
- Sur le serveur, créez une clé :
ssh-keygen -t ed25519 -f ~/.ssh/gitlab_depot -N "" -C "serveur-depot" - Dans GitLab, ouvrez le projet, puis Settings, Repository, et dépliez Deploy keys. Choisissez Add new key et collez le contenu de
~/.ssh/gitlab_depot.pub. Laissez décochée la case qui donne le droit d'écriture : la clé reste en lecture seule. - Dites à SSH d'utiliser cette clé pour GitLab, en ajoutant à
~/.ssh/config:
Host gitlab.com
IdentityFile ~/.ssh/gitlab_depot
IdentitiesOnly yes
- Clonez le dépôt dans
~/appavec son adresse SSH, puis lancez l'application une première fois à la main.
Pour une instance GitLab installée chez vous, remplacez gitlab.com par son nom.
2. Créer la clé du job
Sur votre ordinateur, créez une paire à part, sans phrase de passe, puisque le job l'utilise sans vous. La documentation de GitLab prévient qu'avec une phrase de passe, le job resterait bloqué à la demander.
ssh-keygen -t ed25519 -f gitlab_job -N "" -C "gitlab-ci"
Ajoutez le contenu de gitlab_job.pub sur une nouvelle ligne de ~/.ssh/authorized_keys du compte qui déploie : voir Ajouter une clé SSH sur un serveur Linux. Un compte réservé au déploiement se crée comme décrit dans Créer un utilisateur sous Linux.
3. Relever la clé du serveur
La documentation demande de lancer ssh-keyscan depuis un réseau de confiance, idéalement depuis le serveur lui-même, et jamais dans le job : un relevé fait à chaque exécution ne protège pas contre un faux serveur.
ssh-keyscan -t ed25519 adresse-du-serveur
Comparez l'empreinte, obtenue avec ssh-keyscan -t ed25519 adresse-du-serveur | ssh-keygen -lf -, à celle que vous avez acceptée lors de votre première connexion.
4. Ranger les variables
Dans le projet, ouvrez Settings, CI/CD, dépliez Variables, puis Add variable. Il faut le rôle Maintainer.
| Clé | Type | Contenu |
|---|---|---|
SSH_PRIVATE_KEY | File | tout le fichier gitlab_job, terminé par un retour à la ligne |
SSH_KNOWN_HOSTS | File | la ligne rendue par ssh-keyscan |
SSH_HOST | Variable | admin@adresse-du-serveur |
- Le type File garde la mise en forme sur plusieurs lignes. GitLab précise que la valeur doit finir par un retour à la ligne, sans quoi SSH répond
error in libcrypto. - La visibilité de la clé privée doit être Visible : une clé contient des espaces, que le masquage refuse. Ne faites donc jamais afficher la variable dans un job, par
catou autrement, car elle apparaîtrait dans le journal. - Protect variable : cochez-la sur les trois. Une variable protégée n'est disponible que dans les pipelines des branches et des étiquettes protégées. Une branche de test poussée par n'importe qui ne recevra donc pas la clé.
Supprimez ensuite gitlab_job de votre ordinateur, ou rangez-le dans votre gestionnaire de mots de passe.
5. Écrire le job
Créez .gitlab-ci.yml à la racine du dépôt. Les commandes de préparation sont celles de la documentation, pour une image Debian :
deployer:
stage: deploy
image: debian:trixie-slim
resource_group: production
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
before_script:
- 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
- eval $(ssh-agent -s)
- chmod 400 "$SSH_PRIVATE_KEY"
- ssh-add "$SSH_PRIVATE_KEY"
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- cp "$SSH_KNOWN_HOSTS" ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
script:
- ssh "$SSH_HOST" 'cd ~/app && git pull && docker compose up -d --build'
rulesne lance le job que sur la branche par défaut, en généralmain.resource_grouplimite la concurrence : deux déploiements ne se chevauchent pas.- La branche par défaut est protégée d'office, d'après la documentation des branches protégées. Si vous déployez depuis une autre branche, protégez-la dans Settings, Repository, Branch rules : sans cela, les variables protégées ne lui sont pas transmises.
6. Essayer
Poussez un commit sur la branche par défaut, puis suivez le pipeline dans Build, Pipelines. En cas d'échec, le journal du job montre l'erreur de SSH ou de la commande distante.
Sur un VPS Hubspace
Le port 22 est ouvert depuis Internet, ce dont les exécuteurs de GitLab ont besoin pour joindre le serveur. Le compte à utiliser est admin, qui lance Docker sans sudo ; la connexion se fait par clé seulement. fail2ban bloque une heure une adresse qui échoue cinq fois en dix minutes : une variable mal recopiée peut faire bloquer temporairement l'adresse de l'exécuteur. Les serveurs VPS décrivent ce qui est livré.
Questions fréquentes
Pourquoi le job ne trouve-t-il pas SSH_PRIVATE_KEY ?
Le plus souvent, la variable est protégée et le pipeline tourne sur une branche qui ne l'est pas. Vérifiez la branche, ou la case Protect variable.
Peut-on limiter ce que la clé du job permet ?
Oui. Dans authorized_keys, l'option restrict en tête de la ligne coupe les transferts et le terminal, et command="..." force une commande unique, décrites dans la page de manuel de sshd. Le job ne peut alors lancer que votre script de déploiement.
Comment retirer l'accès ?
Supprimez la ligne de la clé du job dans ~/.ssh/authorized_keys, les variables du projet, puis la clé de déploiement dans Settings, Repository. Le pipeline échoue dès l'exécution suivante.
Articles liés
- Pointer un nom de domaine vers son VPSPointer un nom de domaine ou un sous-domaine vers l'adresse IP de votre VPS avec un enregistrement A, vérifier la propagation et préparer le certificat HTTPS.
- Certificat SSL sur un VPS : Caddy ou CertbotObtenir un certificat SSL gratuit Let's Encrypt sur votre VPS avec Caddy, Traefik ou Certbot, le renouveler sans y penser, et corriger les échecs de validation.
- Déployer sur son VPS avec GitHub ActionsDéployer une application sur son serveur à chaque push avec GitHub Actions et SSH : clé dédiée, secrets du dépôt, clé du serveur et workflow complet.