Déploiement Docker Compose sur VPS
TUTORIAL 8 min read fordnox

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 :

Docker Compose résout tout ça :

Prérequis

É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

  1. Épinglez les versions des images - Utilisez postgres:16-alpine, pas postgres:latest
  2. Utilisez des fichiers .env - Gardez les secrets hors des fichiers compose (voir notre guide de sécurité VPS)
  3. Volumes nommés pour les données - N’utilisez pas de bind mounts pour les bases de données
  4. Health checks partout - Sachez quand les services sont réellement prêts
  5. Limites de ressources - Empêchez les conteneurs incontrôlés de faire tomber votre serveur
  6. Limites de journalisation - Définissez max-size pour éviter de remplir le disque
  7. Utilisez les réseaux - Isolez les services qui n’ont pas besoin de communiquer
  8. 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.

~/docker-compose-vps-guide/get-started

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

Docker Compose VPS Docker déploiement conteneurs tutoriel Docker déploiement VPS

// related guides

Andrius Putna

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.