Déploiement Docker Compose sur VPS
Guide complet pour déployer des applications avec Docker Compose sur un VPS. De l'installation aux configurations multi-conteneurs avec réseaux et volumes.
Déploiement Docker Compose sur VPS
Docker Compose est la façon la plus simple de déployer et gérer des applications sur votre VPS. Si vous cherchez le meilleur VPS pour Docker, consultez d’abord notre comparatif. Ensuite, définissez toute votre stack dans un seul fichier, déployez en une commande, et mettez à jour sans interruption de service.
Pourquoi C’est Important
Les déploiements traditionnels sont pénibles :
- Les dépendances entrent en conflit entre les applications
- Le syndrome du « ça marche sur ma machine »
- Une configuration manuelle complexe pour chaque serveur
- Les rollbacks nécessitent prières et bonne fortune
Docker Compose résout tout ça :
- Environnements isolés - Les applications ne peuvent pas se perturber mutuellement
- Déploiements reproductibles - La même configuration, le même résultat, à chaque fois
- Contrôle de version - Votre infrastructure est du code
- Rollbacks faciles - La version précédente n’est qu’une commande
Prérequis
- Un VPS sous Ubuntu 22.04+ (nous recommandons Hostinger VPS pour leurs images optimisées Docker)
- Connaissances de base de la ligne de commande
- Accès SSH à votre serveur
Étape 1 : Installer Docker
# Supprimer les anciennes versions
sudo apt remove docker docker-engine docker.io containerd runc
# Installer les dépendances
sudo apt update
sudo apt install ca-certificates curl gnupg -y
# Ajouter la clé GPG de Docker
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Ajouter le dépôt
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Installer Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
# Ajouter votre utilisateur au groupe docker (déconnexion/reconnexion requise)
sudo usermod -aG docker $USER
# Vérifier l'installation
docker --version
docker compose version
Déconnectez-vous puis reconnectez-vous pour que les changements de groupe prennent effet.
Étape 2 : Créer la Structure de votre Projet
mkdir -p ~/apps/myapp
cd ~/apps/myapp
Structure recommandée :
myapp/
├── docker-compose.yml # Fichier compose principal
├── docker-compose.prod.yml # Surcharges pour la production
├── .env # Variables d'environnement (ne jamais committer !)
├── .env.example # Modèle pour les variables d'env
├── nginx/
│ └── nginx.conf # Config Nginx personnalisée
├── data/ # Données persistantes (dans .gitignore)
└── logs/ # Journaux applicatifs (dans .gitignore)
Étape 3 : Écrire votre Premier docker-compose.yml
Déployons une stack web complète :
# docker-compose.yml
services:
app:
image: node:20-alpine
working_dir: /app
volumes:
- ./src:/app
- /app/node_modules
command: npm start
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@db:5432/myapp
depends_on:
db:
condition: service_healthy
restart: unless-stopped
networks:
- internal
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: myapp
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- internal
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./certbot/conf:/etc/letsencrypt:ro
- ./certbot/www:/var/www/certbot:ro
depends_on:
- app
restart: unless-stopped
networks:
- internal
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
command: redis-server --appendonly yes
restart: unless-stopped
networks:
- internal
volumes:
postgres_data:
redis_data:
networks:
internal:
driver: bridge
Étape 4 : Utiliser Correctement les Variables d’Environnement
Créez votre fichier .env :
# .env
DB_PASSWORD=your-super-secret-password-here
REDIS_PASSWORD=another-secret
API_KEY=your-api-key
Créez .env.example à titre de documentation :
# .env.example
DB_PASSWORD=
REDIS_PASSWORD=
API_KEY=
Ne committez jamais .env dans git ! Ajoutez-le à .gitignore :
echo ".env" >> .gitignore
echo "data/" >> .gitignore
echo "logs/" >> .gitignore
Étape 5 : Surcharges de Production
Créez un fichier spécifique à la production :
# docker-compose.prod.yml
services:
app:
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
db:
deploy:
resources:
limits:
cpus: '2'
memory: 1G
Déployez avec :
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Étape 6 : Commandes Docker Compose Courantes
# Démarrer tous les services
docker compose up -d
# Afficher les journaux
docker compose logs -f
# Afficher les journaux d'un service spécifique
docker compose logs -f app
# Arrêter tous les services
docker compose down
# Arrêter et supprimer les volumes (ATTENTION - supprime les données !)
docker compose down -v
# Reconstruire et redémarrer
docker compose up -d --build
# Redémarrer un service spécifique
docker compose restart app
# Afficher les conteneurs en cours d'exécution
docker compose ps
# Exécuter une commande dans un conteneur
docker compose exec app sh
# Afficher l'utilisation des ressources
docker stats
Étape 7 : Déploiements Sans Interruption de Service
Pour mettre à jour sans coupure :
# Récupérer les nouvelles images
docker compose pull
# Recréer uniquement les conteneurs modifiés
docker compose up -d --no-deps app
Ou utilisez des mises à jour progressives avec plusieurs réplicas :
services:
app:
deploy:
replicas: 2
update_config:
parallelism: 1
delay: 10s
Étape 8 : Vérifications de Santé
Ajoutez toujours des health checks :
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Vérifiez l’état de santé :
docker compose ps
docker inspect --format='{{json .State.Health}}' container_name
Étape 9 : Gestion des Secrets
Pour les données sensibles, utilisez les secrets Docker ou des gestionnaires de secrets externes :
services:
app:
secrets:
- db_password
- api_key
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
file: ./secrets/api_key.txt
Étape 10 : Stratégie de Sauvegarde
Créez un script de sauvegarde :
#!/bin/bash
# backup.sh
BACKUP_DIR="/backups/$(date +%Y-%m-%d)"
mkdir -p "$BACKUP_DIR"
# Sauvegarder PostgreSQL
docker compose exec -T db pg_dump -U user myapp > "$BACKUP_DIR/db.sql"
# Sauvegarder les volumes
docker run --rm \
-v myapp_postgres_data:/data:ro \
-v "$BACKUP_DIR":/backup \
alpine tar czf /backup/postgres_data.tar.gz /data
# Sauvegarder Redis
docker compose exec -T redis redis-cli BGSAVE
docker cp "$(docker compose ps -q redis)":/data/dump.rdb "$BACKUP_DIR/"
echo "Sauvegarde terminée : $BACKUP_DIR"
Exemples Concrets
WordPress avec Base de Données
services:
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${WP_DB_PASSWORD}
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress_data:/var/www/html
depends_on:
- db
restart: unless-stopped
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${WP_DB_PASSWORD}
volumes:
- db_data:/var/lib/mysql
restart: unless-stopped
volumes:
wordpress_data:
db_data:
Application JavaScript Full-Stack
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
environment:
- REACT_APP_API_URL=http://api:4000
depends_on:
- api
api:
build: ./api
ports:
- "4000:4000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/app
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: pass
POSTGRES_USER: user
POSTGRES_DB: app
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
volumes:
pgdata:
redisdata:
Git Auto-hébergé avec Gitea
services:
gitea:
image: gitea/gitea:latest
ports:
- "3000:3000"
- "222:22"
volumes:
- gitea_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=${DB_PASSWORD}
depends_on:
- db
restart: unless-stopped
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_USER: gitea
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: gitea
restart: unless-stopped
volumes:
gitea_data:
postgres_data:
Bonnes Pratiques
- Épinglez les versions des images - Utilisez
postgres:16-alpine, paspostgres:latest - Utilisez des fichiers .env - Gardez les secrets hors des fichiers compose (voir notre guide de sécurité VPS)
- Volumes nommés pour les données - N’utilisez pas de bind mounts pour les bases de données
- Health checks partout - Sachez quand les services sont réellement prêts
- Limites de ressources - Empêchez les conteneurs incontrôlés de faire tomber votre serveur
- Limites de journalisation - Définissez max-size pour éviter de remplir le disque
- Utilisez les réseaux - Isolez les services qui n’ont pas besoin de communiquer
- depends_on avec conditions - Attendez que les services soient en bonne santé, pas seulement démarrés
Erreurs Courantes à Éviter
❌ Utiliser le tag latest - Les builds deviennent non reproductibles
❌ Stocker des données dans les conteneurs - Les données disparaissent quand le conteneur est supprimé
❌ Committer les fichiers .env - Les secrets se retrouvent dans l’historique git pour toujours
❌ Pas de health checks - depends_on n’attend pas que l’application soit prête
❌ Ignorer les journaux - Ils rempliront votre disque sans limites
❌ Exposer les ports de base de données - N’exposez que ce qui nécessite un accès externe
❌ Exécuter en tant que root - Utilisez la directive USER dans les Dockerfiles
❌ Pas de politique de redémarrage - Les conteneurs ne redémarrent pas après un crash
Conseils de Débogage
# Voir pourquoi un conteneur échoue
docker compose logs app --tail=100
# Ouvrir un shell dans un conteneur en cours d'exécution
docker compose exec app sh
# Ouvrir un shell dans un conteneur arrêté
docker compose run app sh
# Inspecter les détails d'un conteneur
docker inspect $(docker compose ps -q app)
# Vérifier la connectivité réseau
docker compose exec app ping db
# Afficher les variables d'environnement
docker compose exec app env
FAQ
Combien de RAM me faut-il ?
Pour les petits projets, 2 Go suffisent généralement. Chaque conteneur a une surcharge, donc comptez ~100 Mo par conteneur plus les besoins réels de l’application. Les plans Hostinger VPS démarrent à 4 Go, ce qui gère la plupart des stacks confortablement.
Dois-je utiliser Docker Compose ou Kubernetes ?
Docker Compose pour les déploiements mono-serveur (la plupart des gens). Kubernetes quand vous avez besoin de clusters multi-nœuds, d’auto-scaling, ou d’une équipe DevOps dédiée. N’overcomplexifiez pas.
Comment mettre à jour une application en cours d’exécution ?
# Récupérer les dernières images
docker compose pull
# Recréer les conteneurs modifiés
docker compose up -d
Pour les builds personnalisés : docker compose up -d --build
Puis-je utiliser Docker Compose avec Nginx Proxy Manager ?
Oui ! N’exposez pas les ports directement, mettez simplement les conteneurs sur le même réseau que NPM. Consultez notre guide reverse proxy.
Comment persister les données ?
Utilisez des volumes nommés (Docker gère l’emplacement) ou des bind mounts (vous spécifiez le chemin). Les volumes nommés sont recommandés pour les bases de données.
Quelle est la différence entre up et start ?
up crée et démarre les conteneurs. start démarre uniquement les conteneurs existants arrêtés. Utilisez toujours up -d.
Prochaines étapes : Configurez des sauvegardes automatisées pour protéger vos données Docker, et ajoutez une surveillance pour suivre l’état de vos conteneurs.
Ready to get started?
Get the best VPS hosting deal today. Hostinger offers 4GB RAM VPS starting at just $4.99/mo.
Get Hostinger VPS — $4.99/mo// up to 75% off + free domain included
// related topics
// related guides
$1 VPS Hosting 2026: Cheapest VPS Servers Starting at $1/Month
Looking for $1 VPS hosting? Compare the cheapest VPS providers starting from $1-3/month. Real specs, no hidden fees, honest reviews of budget VPS options.
tutorialCaddy Reverse Proxy Guide 2026: Automatic HTTPS Made Easy
Set up Caddy as a reverse proxy with automatic HTTPS, zero-config SSL, and simple Caddyfile syntax. Complete VPS deployment guide.
tutorialCloudflare Tunnel VPS Guide 2026: Expose Services Without Opening Ports
Set up Cloudflare Tunnel on your VPS to expose web apps securely without opening ports or revealing your server IP. Complete guide with Docker and DNS config.
tutorialCoolify VPS Setup Guide 2026: Self-Hosted Vercel Alternative
Deploy Coolify on your VPS for a self-hosted Vercel/Netlify experience. Complete setup guide with Docker, SSL, and app deployments.
Andrius Putna
I am Andrius Putna. Geek. Since early 2000 in love tinkering with web technologies. Now AI. Bridging business and technology to drive meaningful impact. Combining expertise in customer experience, technology, and business strategy to deliver valuable insights. Father, open-source contributor, investor, 2xIronman, MBA graduate.
// last updated: February 6, 2026. Disclosure: This article may contain affiliate links.