Docker en production sur un VPS : ce qui casse et comment corriger
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 :
- 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.
- 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.
- 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
:latesten production. Utilisez des tags de version spécifiques commepostgres:16.4ou même des digests SHA. - Pulls planifiés : exécutez
docker compose pull && docker compose up -dsur 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 pruneest 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-stoppedouon-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 dockeretdocker 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.