Docker en production sur un VPS : ce qui casse et comment corriger

13 min de lecture·Matthieu·productionsecurityvpsdocker-composedocker|

Docker tourne sur votre portable. Sur un VPS public, il contourne le pare-feu, remplit le disque de logs, exécute tout en root et n'a aucune stratégie de mise à jour. Voici les 8 problèmes à résoudre.

Vous avez installé Docker sur votre VPS. Vous avez lancé docker compose up. Votre application est en ligne. C'est terminé, non ?

Pas tout à fait. Sur votre portable, personne ne scanne vos ports, l'espace disque est suffisant et la sécurité importe peu. Sur un VPS exposé à Internet, les réglages par défaut de Docker jouent contre vous.

Cette page couvre les 8 problèmes que vous allez rencontrer et renvoie vers un guide dédié pour chacun. Parcourez-la, identifiez ce qui s'applique à votre serveur, suivez le guide détaillé.

Prérequis

Ce guide part du principe que vous connaissez les bases de Docker. Si vous avez besoin d'une mise à niveau :

  • Commandes et concepts Docker
  • Applications multi-services avec Compose

Cet article cible Debian 12 et Ubuntu 24.04 avec Docker Engine 29.x et Compose v2 (version 5.x).

Qu'est-ce qui casse quand on exécute Docker sur un VPS public ?

Huit choses cassent quand vous passez Docker du développement à un VPS public : votre pare-feu cesse de fonctionner, les conteneurs tournent en root avec un accès complet à l'hôte, les logs remplissent votre disque sans rotation, le réseau des conteneurs entre en conflit avec celui de l'hôte, les services n'ont ni limites de ressources ni health checks, les volumes n'ont aucune stratégie de sauvegarde, les ports sont exposés sans TLS et les images de conteneurs deviennent obsolètes sans plan de mise à jour. Ce sont les réglages par défaut de Docker. Chacun d'entre eux vous posera problème en production.

Aperçu rapide avant les guides détaillés :

# Problème Commande de diagnostic Risque
1 Contournement du pare-feu sudo iptables -L DOCKER-USER -n Critique
2 Conteneurs root docker info --format '{{.SecurityOptions}}' Critique
3 Disque plein à cause des logs du -sh /var/lib/docker/containers/*/*-json.log Élevé
4 Conflits réseau docker network ls Moyen
5 Pas de limites de ressources docker stats --no-stream Élevé
6 Pas de sauvegarde des volumes docker volume ls Élevé
7 Pas de reverse proxy / TLS ss -tlnp | grep -E ':80|:443' Critique
8 Images obsolètes docker compose images Moyen

Lancez ces commandes sur votre serveur maintenant. Si une sortie vous surprend, lisez la section correspondante ci-dessous.

Docker contourne-t-il votre pare-feu ?

Oui. Docker manipule iptables directement, en insérant des règles dans les tables nat et filter qui sont évaluées avant que UFW ou firewalld ne voie le trafic. Quand vous publiez un port avec -p 8080:80, ce port est ouvert à tout Internet, même si vos règles UFW disent deny incoming.

Vérifiez si cela vous concerne :

sudo iptables -L DOCKER-USER -n -v

Si la sortie montre une chaîne vide ou seulement une règle RETURN inconditionnelle sans filtrage, chaque port publié est grand ouvert.

La cause : les paquets destinés aux conteneurs Docker passent par la chaîne FORWARD et la chaîne DOCKER. UFW opère sur la chaîne INPUT. Les deux ne se croisent jamais.

Le correctif immédiat le plus simple est de lier les ports publiés à 127.0.0.1 uniquement :

ports:
  - "127.0.0.1:8080:80"

Cela rend le port accessible uniquement depuis l'hôte lui-même. Combinez avec un reverse proxy pour gérer le trafic externe.

Pour un guide complet sur la chaîne DOCKER-USER, l'intégration UFW et la configuration nftables.

Exécuter Docker en root est-il dangereux sur un VPS ?

Par défaut, le démon Docker tourne en root et les conteneurs tournent en root dans leurs espaces de noms. Si un attaquant s'échappe d'un conteneur, il atterrit sur l'hôte en root. Sur un VPS public, c'est un chemin direct vers la compromission totale du serveur.

Vérifiez votre configuration actuelle :

docker info --format '{{.SecurityOptions}}'

Cherchez name=rootless dans la sortie. S'il n'y est pas, votre démon tourne en root.

Vérifiez aussi si vos conteneurs tournent en root en interne :

docker ps -q | xargs -I {} docker exec {} id

Si vous voyez uid=0(root) pour la plupart des conteneurs, ils tournent en root à l'intérieur du conteneur. Une image qui définit USER appuser dans son Dockerfile affichera un uid non-root à la place.

Vous avez trois couches de défense :

  1. Le mode rootless exécute l'intégralité du démon Docker sous un utilisateur non-root. Même une évasion de conteneur atterrit en tant qu'utilisateur non privilégié sur l'hôte.
  2. Les profils seccomp restreignent les appels système que les conteneurs peuvent utiliser. Docker fournit un profil par défaut qui bloque environ 44 appels système dangereux, mais vous pouvez le renforcer.
  3. AppArmor / SELinux ajoute un contrôle d'accès obligatoire par-dessus tout le reste.

Configuration complète du mode rootless, profils seccomp personnalisés et no-new-privileges.

Pourquoi les conteneurs Docker remplissent-ils votre disque ?

Le driver de logs par défaut de Docker est json-file sans limite de taille ni rotation. Chaque ligne que votre application écrit sur stdout est stockée dans /var/lib/docker/containers/<id>/<id>-json.log. Une application web active peut générer des gigaoctets de logs en quelques jours.

Vérifiez l'espace utilisé par les logs en ce moment :

sudo du -sh /var/lib/docker/containers/*/*-json.log 2>/dev/null | sort -rh | head -5

Sur un VPS qui tourne depuis quelques semaines sans rotation des logs, vous pourriez voir une sortie comme :

4.2G    /var/lib/docker/containers/a1b2c3.../a1b2c3...-json.log
1.8G    /var/lib/docker/containers/d4e5f6.../d4e5f6...-json.log
256M    /var/lib/docker/containers/g7h8i9.../g7h8i9...-json.log

Les logs ne sont pas les seuls consommateurs d'espace. Vérifiez l'utilisation disque globale de Docker :

docker system df

Sortie typique sur un serveur avec 5 services :

TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          12        5         4.2GB     2.8GB (66%)
Containers      8         5         52MB      12MB (23%)
Local Volumes   6         4         1.1GB     245MB (22%)
Build Cache     18        0         890MB     890MB (100%)

Ce cache de build est récupérable à 100 %. Ces 7 images inutilisées prennent 2,8 Go. Sur un disque de VPS de 40 Go, ça s'accumule vite.

La solution est en deux parties : configurer la rotation des logs dans /etc/docker/daemon.json et mettre en place un nettoyage périodique des images inutilisées et du cache de build.

Configuration complète de la rotation des logs, supervision du disque et nettoyage automatisé :

Comment fonctionne le réseau Docker sur un VPS unique ?

Docker crée son propre réseau bridge (172.17.0.0/16 par défaut) et gère les IP des conteneurs en interne. Sur un VPS, cela peut entrer en conflit avec votre réseau hôte, vos sous-réseaux VPN ou d'autres services.

Voyez quels réseaux Docker a créés :

docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
a1b2c3d4e5f6   bridge    bridge    local
f6e5d4c3b2a1   host      host      local
9i8h7g6f5e4d   none      null      local

Chaque docker compose up crée un réseau supplémentaire. Après quelques projets, vous pourriez avoir une douzaine de réseaux avec des sous-réseaux qui se chevauchent.

Décisions clés pour le réseau sur un VPS :

  • Mode bridge (par défaut) : les conteneurs obtiennent des IP internes, les ports sont publiés via iptables. Fonctionne pour la plupart des configurations. Ajoute une couche NAT.
  • Mode host : les conteneurs partagent directement la pile réseau de l'hôte. Pas de surcharge NAT, mais pas d'isolation des ports. Utile pour les services sensibles aux performances.
  • Réseaux bridge personnalisés : les conteneurs sur le même réseau personnalisé peuvent communiquer par nom de conteneur. C'est ce que Compose crée automatiquement.

Le point important sur un VPS : définissez vos sous-réseaux explicitement dans docker-compose.yml au lieu de laisser Docker choisir. Cela évite les conflits avec les réseaux internes de votre hébergeur.

Guide détaillé sur bridge vs host, sous-réseaux personnalisés et DNS inter-conteneurs :

Que se passe-t-il sans limites de ressources ni health checks ?

Sans limites de mémoire, un seul conteneur avec une fuite mémoire consommera toute la RAM disponible, déclenchera l'OOM killer de Linux et fera tomber des conteneurs sans rapport, voire le démon SSH. Sans health checks, Docker n'a aucun moyen de savoir qu'un conteneur est en panne. Il reste « running » tout en renvoyant des erreurs.

Vérifiez si vos conteneurs ont des limites définies :

docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.CPUPerc}}"

Si la colonne MEM % affiche des valeurs mais que vous n'avez jamais défini de limites, ces pourcentages sont calculés par rapport à la RAM totale de l'hôte. Un conteneur qui affiche 45 % utilise 45 % de la mémoire totale de votre VPS, et rien ne l'empêche d'en prendre davantage.

La configuration de production minimale dans votre docker-compose.yml :

services:
  app:
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "1.0"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s
    restart: unless-stopped

La politique restart: unless-stopped redémarre automatiquement les conteneurs plantés mais respecte les arrêts manuels. Le healthcheck permet à Docker de marquer les conteneurs en mauvaise santé et de les redémarrer selon le nombre de tentatives.

Guide complet sur les limites de ressources Compose, les patterns de healthcheck et les politiques de redémarrage :

Comment sauvegarder les volumes Docker ?

Les volumes Docker conservent les données en dehors des conteneurs. Si un volume est supprimé ou corrompu, votre base de données, vos fichiers uploadés ou votre configuration disparaissent. Docker n'a pas de mécanisme de sauvegarde intégré pour les volumes.

Listez vos volumes et leurs tailles :

docker system df -v | grep -A 100 "Local Volumes space usage"

Ou vérifiez les points de montage individuels :

docker volume ls -q | xargs -I {} docker volume inspect {} --format '{{.Name}}: {{.Mountpoint}}'

Les points de montage sont sous /var/lib/docker/volumes/ par défaut. Vous pouvez les sauvegarder avec les outils Linux standard, mais vous devez arrêter ou mettre en pause le conteneur d'abord pour éviter des instantanés incohérents. Pour les bases de données, une copie du système de fichiers d'une base en cours d'exécution n'est pas une sauvegarde fiable. Il faut d'abord faire un dump.

Stratégies de sauvegarde, procédures de restauration et planification automatisée :

Comment exposer les services Docker avec TLS ?

Publier les ports directement avec -p 443:443 sur chaque conteneur ne passe pas à l'échelle au-delà d'un service. Vous avez besoin d'un reverse proxy qui termine le TLS, route le trafic vers le bon conteneur et gère le renouvellement des certificats.

Vérifiez ce qui écoute actuellement sur votre VPS :

ss -tlnp | grep -E ':80|:443'

Si vous voyez vos conteneurs d'application se lier directement aux ports 80 ou 443, ils sont exposés sans couche proxy. Cela signifie que chaque service a besoin de sa propre gestion de certificats, et vous ne pouvez pas héberger plusieurs domaines sur un seul VPS.

Trois options de reverse proxy dominent l'écosystème Docker :

Proxy Auto-discovery TLS automatique Style de configuration
Traefik Oui (labels Docker) Let's Encrypt intégré Labels + YAML
Caddy Via plugin Automatique par défaut Caddyfile
Nginx Proxy Manager Socket Docker Interface Let's Encrypt Interface web

Traefik est le choix le plus courant pour les déploiements Docker-natifs parce qu'il lit les labels des conteneurs et génère les règles de routage automatiquement. Pas de fichiers de configuration à mettre à jour quand vous ajoutez un service.

Comparaison, guides d'installation et configuration TLS pour chaque option :

Quelle est la stratégie de mise à jour des conteneurs Docker sur un VPS ?

Les images Docker ne se mettent pas à jour toutes seules. Si vous exécutez postgres:16 et qu'un correctif de sécurité sort dans postgres:16.4, votre conteneur continue de tourner avec l'ancienne image tant que vous ne la tirez pas et ne recréez pas le conteneur explicitement.

Vérifiez quelles images vos services utilisent :

docker compose images

Comparez les digests des images avec les dernières versions disponibles :

docker compose pull --dry-run 2>&1

Si une image apparaît comme « pulled » dans la sortie du dry-run, votre version en cours est obsolète.

Les décisions clés :

  • Figer les tags d'images : n'utilisez jamais :latest en production. Utilisez des tags de version spécifiques comme postgres:16.4 ou même des digests SHA.
  • Pulls planifiés : exécutez docker compose pull && docker compose up -d sur un planning, mais testez d'abord les mises à jour en staging.
  • Redémarrages sans interruption : utilisez les health checks et docker compose up -d --no-deps <service> pour mettre à jour un service à la fois.
  • Analyse des images : des outils comme Trivy analysent vos images à la recherche de CVE connues avant le déploiement.

Stratégies de mise à jour, patterns de versionnage d'images et déploiement sans interruption :

Faut-il Kubernetes pour faire tourner Docker en production ?

Non. Docker Compose est un outil de déploiement prêt pour la production pour les charges de travail sur un seul serveur. Kubernetes résout l'orchestration multi-nœuds, le scaling automatique et l'auto-réparation sur un cluster. Si votre application tourne sur un seul VPS, Compose vous donne tout ce dont vous avez besoin sans la charge opérationnelle de Kubernetes.

Où Compose fonctionne :

  • Un VPS unique avec 3 à 15 conteneurs
  • Patterns de trafic statiques ou prévisibles
  • Petite équipe sans ingénieurs plateforme dédiés
  • Services qui tolèrent quelques secondes d'interruption pendant les mises à jour

Où vous dépassez Compose :

  • Plusieurs serveurs nécessaires pour la haute disponibilité
  • Auto-scaling basé sur les pics de trafic
  • Service meshes avec des centaines de microservices
  • Exigences de zéro interruption avec déploiements blue-green entre les nœuds

La solution intermédiaire légère est K3s, un Kubernetes allégé qui tourne sur un seul VPS avec environ 512 Mo de surcharge RAM. Mais pour la plupart des projets perso, MVP SaaS et petites applications de production, Compose est le bon outil.

De combien de RAM un VPS a-t-il besoin pour Docker en production ?

Un VPS faisant tourner Docker en production a besoin d'au minimum 4 Go de RAM pour 3 à 5 conteneurs. Le démon Docker lui-même utilise environ 100 à 200 Mo. Chaque conteneur ajoute sa propre empreinte mémoire par-dessus. Sans limites de mémoire définies, un seul conteneur défaillant peut tout consommer.

Taille du VPS Conteneurs Adapté pour
4 Go de RAM 3-5 légers Blog, API, base de données, Redis
8 Go de RAM 5-10 mixtes MVP SaaS, services multiples, stack de monitoring
16 Go de RAM 10-20 Projets multiples, runners CI, bases de données lourdes
32 Go de RAM 20+ Inférence IA, grandes bases de données, serveurs de build

Le stockage compte autant que la RAM. Les images Docker, les volumes, les logs et le cache de build s'accumulent. Prévoyez au moins 40 Go de stockage NVMe et mettez en place la supervision décrite dans dès le premier jour.

Le CPU est rarement le goulot d'étranglement pour les services web conteneurisés. 4 vCPU suffisent pour la plupart des charges de travail. Exceptions : transcodage vidéo, inférence IA et serveurs de build.

Pour un VPS avec stockage NVMe dimensionné pour les charges de travail Docker en production, voir les offres VPS Virtua Cloud.

Checklist de production

Avant de passer en production avec Docker sur un VPS, vérifiez chaque point :

  • Les règles de pare-feu bloquent tous les ports publiés par Docker sauf via le reverse proxy
  • Les conteneurs tournent en tant qu'utilisateurs non-root quand c'est possible
  • Le démon Docker tourne en mode rootless ou les conteneurs utilisent seccomp + no-new-privileges
  • La rotation des logs est configurée dans /etc/docker/daemon.json
  • docker system prune est exécuté sur un planning (cron hebdomadaire)
  • Chaque service a des limites de mémoire et CPU dans docker-compose.yml
  • Chaque service a un health check
  • La politique de redémarrage est définie (unless-stopped ou on-failure)
  • Les volumes contenant des données importantes ont des sauvegardes automatisées
  • Un reverse proxy gère la terminaison TLS et le renouvellement des certificats
  • Les tags d'images sont figés sur des versions spécifiques, pas :latest
  • Vous avez une procédure de mise à jour testée pour tirer les nouvelles images
  • journalctl -u docker et docker logs <container> fonctionnent et vous savez où chercher

Si vous ne pouvez pas cocher chaque case, parcourez les articles liés dans chaque section ci-dessus.


Copyright 2026 Virtua.Cloud. Tous droits réservés. Ce contenu est une création originale de l'équipe Virtua.Cloud. Toute reproduction, republication ou redistribution sans autorisation écrite est interdite.

Prêt à essayer ?

Exécutez Docker en production sur un VPS fiable.

Voir les offres VPS
Docker en production sur un VPS : 8 problèmes à corriger