Avancé ⏱ 30 min de mise en œuvre Mis à jour le 11 août 2026

Héberger un registre Docker privé sur son VPS

Garder ses images Docker privées sur son propre serveur plutôt que sur Docker Hub. Un registre auto-hébergé le permet. Voici comment le déployer, HTTPS et authentification compris.

Conserver ses images Docker privées sur sa propre infrastructure permet de maîtriser leur stockage, leur disponibilité et leur confidentialité. Un registre auto-hébergé sert de dépôt central pour les images internes utilisées par les développeurs, les pipelines CI/CD et les serveurs de production.

Ce guide présente le déploiement d’un registre Docker privé simple avec l’image officielle registry:2. Le registre sera protégé par une authentification htpasswd, exposé uniquement derrière un reverse proxy HTTPS et stockera ses données sur un volume persistant du VPS.

Pourquoi héberger un registre Docker privé ?

Un registre privé répond d’abord à un besoin de confidentialité. Les images d’une entreprise peuvent contenir du code propriétaire, des dépendances internes, des binaires métier ou des informations sur l’architecture d’une application. Elles ne doivent pas être publiées dans un dépôt public par erreur.

L’auto-hébergement réduit également la dépendance envers Docker Hub, GHCR ou un autre service tiers. Vous gardez le contrôle sur la disponibilité du registre, les politiques de conservation et les éventuelles limitations de téléchargement. Les serveurs et les pipelines ne dépendent plus directement des quotas ou des changements de politique d’une plateforme externe.

Dans une chaîne CI/CD classique, le pipeline construit une image, lui attribue un tag, puis la pousse vers le registre privé. Le serveur de production s’authentifie ensuite auprès du même registre pour récupérer l’image. Si ces composants sont hébergés sur la même infrastructure, les transferts peuvent rester dans un environnement réseau maîtrisé.

Pour une organisation française, un VPS localisé en France facilite aussi une démarche de souveraineté et de conformité RGPD. Les VPS TalCloud s’inscrivent dans cette logique avec des serveurs en France, du stockage NVMe, une protection Anti-DDoS Netrix et un support humain.

Registre officiel ou plateforme complète ?

L’image officielle registry:2, issue du projet Distribution, fournit un registre volontairement minimaliste. Elle permet de pousser, stocker et télécharger des images conformes au protocole Docker Registry HTTP API V2.

Elle ne fournit toutefois aucune interface web, aucun catalogue convivial et aucune gestion avancée des utilisateurs ou des projets. L’authentification htpasswd convient à une petite équipe, mais elle ne remplace pas un système complet de rôles et de permissions.

Harbor ajoute notamment une interface, des projets, des politiques d’accès, de la réplication et différentes fonctions de sécurité. Il demande davantage de ressources et d’administration. GitLab et Gitea peuvent également proposer un registre intégré, pratique lorsque le code et les pipelines sont déjà gérés sur ces plateformes.

Ce guide reste centré sur un registre simple, persistant et correctement sécurisé.

Prérequis

Vous devez disposer des éléments suivants :

  • Un VPS Linux avec suffisamment d’espace disque pour vos images
  • Docker Engine et le plugin Docker Compose (voir installer Docker sur un VPS)
  • Un nom de domaine, par exemple registry.example.fr
  • Un enregistrement DNS pointant vers l’adresse IP du VPS
  • Un reverse proxy comme Nginx, Caddy ou Traefik
  • Un certificat TLS valide pour le domaine
  • Les ports 80 et 443 accessibles depuis Internet

Le port interne 5000 du registre ne doit pas être exposé publiquement. Il sera lié uniquement à 127.0.0.1, puis utilisé par le reverse proxy local.

Créer l’authentification htpasswd

Créez les répertoires qui contiendront les utilisateurs et les données persistantes :

mkdir -p auth data

Utilisez ensuite l’image Apache HTTP Server pour générer un fichier htpasswd avec un mot de passe chiffré en bcrypt :

docker run --rm -it \
  -v "$PWD/auth:/auth" \
  --entrypoint htpasswd \
  httpd:2 \
  -B /auth/htpasswd deploy

La commande demande le mot de passe de l’utilisateur deploy sans l’inscrire directement dans l’historique du shell.

Pour ajouter un utilisateur supplémentaire, utilisez l’option -B sans -c :

docker run --rm -it \
  -v "$PWD/auth:/auth" \
  --entrypoint htpasswd \
  httpd:2 \
  -B /auth/htpasswd ci

Protégez ce fichier, car il contient les empreintes des mots de passe :

chmod 600 auth/htpasswd

Déployer le registre avec Docker Compose

Créez un fichier compose.yaml :

services:
  registry:
    image: registry:2
    container_name: registry
    restart: unless-stopped
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
      REGISTRY_STORAGE_DELETE_ENABLED: "true"
    volumes:
      - ./data:/var/lib/registry
      - ./auth:/auth:ro
    ports:
      - "127.0.0.1:5000:5000"

Démarrez le service :

docker compose up -d

Contrôlez ensuite son état et ses journaux :

docker compose ps
docker compose logs --tail=100 registry

Le montage ./data:/var/lib/registry rend les images persistantes après un redémarrage ou une recréation du conteneur. Le fichier d’authentification est monté en lecture seule.

Configurer HTTPS avec un reverse proxy

HTTPS est obligatoire pour un registre distant correctement configuré. Docker refuse normalement les registres servis en HTTP, sauf lorsqu’ils sont ajoutés aux insecure-registries du moteur. Cette exception affaiblit la sécurité et doit être évitée.

Voici un exemple de bloc Nginx :

server {
    listen 443 ssl http2;
    server_name registry.example.fr;

    ssl_certificate /etc/letsencrypt/live/registry.example.fr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/registry.example.fr/privkey.pem;

    client_max_body_size 0;
    proxy_request_buffering off;

    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        add_header Docker-Distribution-Api-Version "registry/2.0" always;
    }
}

client_max_body_size 0 évite que Nginx refuse les couches volumineuses. proxy_request_buffering off permet de transmettre les envois au registre sans attendre leur mise en mémoire tampon complète.

Après avoir installé le certificat et activé la configuration, vérifiez puis rechargez Nginx :

sudo nginx -t
sudo systemctl reload nginx

Le pare-feu du VPS doit autoriser HTTPS, mais pas le port 5000 depuis Internet.

Se connecter et utiliser le registre

Authentifiez votre poste auprès du registre :

docker login registry.example.fr

Docker demande le nom d’utilisateur et le mot de passe créés avec htpasswd. Dans un script, préférez --password-stdin pour ne pas exposer le secret dans les arguments du processus :

printf '%s' "$REGISTRY_PASSWORD" | \
  docker login registry.example.fr \
  --username "$REGISTRY_USER" \
  --password-stdin

Pour publier une image locale, son nom doit commencer par le domaine du registre :

docker tag monapplication:latest registry.example.fr/monapplication:latest
docker push registry.example.fr/monapplication:latest

Un autre serveur authentifié peut ensuite la télécharger :

docker pull registry.example.fr/monapplication:latest

Utilisez des tags immuables, comme un numéro de version ou un hash Git, plutôt que de dépendre uniquement de latest :

docker tag monapplication:latest registry.example.fr/monapplication:1.4.2
docker push registry.example.fr/monapplication:1.4.2

Intégrer le registre à la CI/CD

Le pipeline doit suivre quatre étapes : construire l’image, se connecter au registre, appliquer un tag unique et pousser l’image. Nos guides sur GitLab CI et GitHub Actions détaillent cette automatisation.

Stockez le nom d’utilisateur et le mot de passe dans le gestionnaire de secrets de votre plateforme CI/CD. Ne placez jamais ces identifiants dans le dépôt, le fichier Compose ou l’image Docker.

Un enchaînement générique ressemble à ceci :

docker build -t registry.example.fr/monapplication:"$CI_COMMIT_SHA" .
printf '%s' "$REGISTRY_PASSWORD" | docker login registry.example.fr \
  -u "$REGISTRY_USER" --password-stdin
docker push registry.example.fr/monapplication:"$CI_COMMIT_SHA"

Le serveur de production peut alors récupérer exactement cette version, ce qui rend les déploiements reproductibles et facilite les retours en arrière.

Nettoyage, maintenance et sauvegardes

Les couches s’accumulent avec chaque nouvelle version. Supprimer un tag ou un manifeste ne libère pas immédiatement l’espace disque. La variable REGISTRY_STORAGE_DELETE_ENABLED autorise les suppressions via l’API, mais une opération de garbage collection reste nécessaire pour effacer les blobs devenus inutilisés.

Effectuez d’abord une simulation pendant une interruption des écritures :

docker compose stop registry
docker compose run --rm registry \
  /bin/registry garbage-collect --dry-run \
  /etc/distribution/config.yml

Lancez ensuite le nettoyage réel, puis redémarrez le service :

docker compose run --rm registry \
  /bin/registry garbage-collect \
  /etc/distribution/config.yml
docker compose up -d

N’exécutez pas la garbage collection pendant des push actifs. Une couche supprimée alors qu’elle est encore utilisée pourrait rendre une image incomplète.

Surveillez régulièrement l’espace disponible :

df -h
du -sh data

Sauvegardez le volume data, le fichier auth/htpasswd, la configuration Compose, le reverse proxy et les éléments nécessaires au renouvellement TLS. Notre guide sur les sauvegardes chiffrées avec restic aide à automatiser ces copies. Testez aussi la restauration sur une machine isolée.

Enfin, HTTPS et l’authentification sont indispensables. Sans ces deux protections, un tiers pourrait intercepter des identifiants, télécharger des images confidentielles ou pousser des images compromises. Pour renforcer l’installation, limitez les accès réseau, utilisez des comptes distincts pour la CI et les administrateurs, renouvelez les secrets et maintenez Docker, le registre et le reverse proxy à jour.