Catégorie : PHASE 2 : Docker & Sécurité des Données

  • 🏗️ Architecture Docker Compose & Gestion des Secrets

    Ce que j’ai fait

    1. C’est quoi Docker Compose ?

    Dans l’étape précédente, j’ai installé Docker. Mais mon site a besoin de 3 logiciels qui travaillent ensemble :

    • MariaDB → la base de données (stocke les articles, les pages, etc.)
    • WordPress → le moteur du site (génère les pages)
    • Nginx → le serveur web (distribue les pages aux visiteurs)

    Lancer ces 3 logiciels un par un avec des commandes à rallonge, ce serait galère. Docker Compose permet de tout décrire dans un seul fichier et de tout démarrer en une commande.

    2. Qui parle avec qui ?

    Avant de coder, j’ai réfléchi à comment ces 3 services doivent communiquer. L’idée c’est que la base de données ne soit jamais accessible depuis Internet.

    Internet (les visiteurs)
           │
           ▼
    ┌────────────┐
    │   Nginx    │  ← Le seul visible de l'extérieur
    └─────┬──────┘
          │
    ┌─────┴──────┐
    │ WordPress  │  ← Fabrique les pages
    └─────┬──────┘
          │
    ┌─────┴──────┐
    │  MariaDB   │  ← Invisible depuis Internet
    └────────────┘

    Pour ça, j’ai créé deux réseaux internes dans Docker :

    • frontend → relie Nginx et WordPress
    • backend → relie WordPress et MariaDB

    Résultat : Nginx ne peut pas toucher à la base de données, et personne sur Internet ne le peut non plus.

    3. Les mots de passe (fichier .env)

    Les mots de passe ne doivent jamais apparaître dans le code, ni sur GitHub. La solution : les mettre dans un fichier .env séparé, qui reste uniquement sur le serveur.

    cd ~
    mkdir -p portfolio && cd portfolio
    nano .env

    Dans ce fichier, j’ai mis toutes les infos sensibles sous cette forme :

    MYSQL_ROOT_PASSWORD=mot_de_passe_genere_par_keepass
    MYSQL_DATABASE=nom_de_la_base
    MYSQL_USER=nom_utilisateur_base
    MYSQL_PASSWORD=autre_mot_de_passe_genere
    
    WORDPRESS_DB_HOST=db:3306
    WORDPRESS_DB_NAME=nom_de_la_base
    WORDPRESS_DB_USER=nom_utilisateur_base
    WORDPRESS_DB_PASSWORD=autre_mot_de_passe_genere

    Ensuite j’ai verrouillé le fichier pour que seul mon utilisateur puisse le lire :

    chmod 600 .env

    4. Le fichier docker-compose.yml

    C’est le fichier qui décrit toute mon infrastructure :

    nano docker-compose.yml
    services:
    
      db:
        image: mariadb:10.11
        container_name: portfolio-db
        restart: unless-stopped
        environment:
          MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
          MYSQL_DATABASE: ${MYSQL_DATABASE}
          MYSQL_USER: ${MYSQL_USER}
          MYSQL_PASSWORD: ${MYSQL_PASSWORD}
        volumes:
          - db_data:/var/lib/mysql
        networks:
          - backend
    
      wordpress:
        image: wordpress:6.7-php8.3-fpm
        container_name: portfolio-wp
        restart: unless-stopped
        depends_on:
          - db
        environment:
          WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
          WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
          WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
          WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
        volumes:
          - wp_data:/var/www/html
        networks:
          - frontend
          - backend
    
      webserver:
        image: nginx:1.27
        container_name: portfolio-nginx
        restart: unless-stopped
        depends_on:
          - wordpress
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - wp_data:/var/www/html:ro
          - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
        networks:
          - frontend
    
    volumes:
      db_data:
      wp_data:
    
    networks:
      frontend:
      backend:

    Ce qu’il faut retenir :

    • Les ${…} vont chercher les valeurs dans le fichier .env automatiquement
    • mariadb:10.11 et pas mariadb:latest → je fixe la version pour éviter les mauvaises surprises
    • Pas de ports: sur db → la base de données n’est pas accessible de l’extérieur
    • :ro sur les volumes Nginx = lecture seule (il peut lire les fichiers mais pas les modifier)
    • restart: unless-stopped = les conteneurs redémarrent tout seuls si le serveur reboot

    5. La configuration de Nginx

    Nginx a besoin de savoir comment transmettre les demandes des visiteurs à WordPress.

    mkdir -p ~/portfolio/nginx
    nano ~/portfolio/nginx/default.conf
    server {
        listen 80;
        server_name _;
    
        root /var/www/html;
        index index.php index.html;
    
        location / {
            try_files $uri $uri/ /index.php?$args;
        }
    
        location ~ \.php$ {
            fastcgi_pass wordpress:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
            expires 30d;
            add_header Cache-Control "public, no-transform";
        }
    
        location ~ /\.ht {
            deny all;
        }
    }

    En gros :

    • Si un visiteur demande une page → Nginx la transmet à WordPress
    • Si c’est une image ou un fichier CSS → Nginx l’envoie directement (plus rapide)
    • Les fichiers cachés (.htaccess etc.) sont bloqués

    6. Lancement

    cd ~/portfolio
    
    # Tout démarrer
    docker compose up -d
    
    # Vérifier que les 3 conteneurs tournent
    docker compose ps
    
    # Lire les logs pour voir si tout va bien
    docker compose logs

    Si les 3 conteneurs affichent « running », c’est gagné. 🎉

    7. Commandes utiles pour la suite

    # Tout arrêter
    docker compose down
    
    # Voir les logs d'un seul service
    docker compose logs db
    
    # Redémarrer après un changement
    docker compose down && docker compose up -d
  • 🐳 Installation et configuration de Docker

    Ce que j’ai fait

    1. Pourquoi Docker ?

    Sans Docker, pour faire tourner un site WordPress il faudrait installer manuellement PHP, Nginx, MariaDB direct sur le serveur. Chaque logiciel peut entrer en conflit avec les autres, et une mise à jour peut tout casser.

    Docker permet d’isoler chaque service dans un conteneur : une boîte fermée qui contient tout ce dont le service a besoin pour fonctionner. Si un conteneur casse, les autres ne sont pas affectés.

    2. Installation

    Debian propose un paquet docker.io dans ses dépôts, mais il est souvent en retard de plusieurs versions. J’installe donc Docker depuis son dépôt officiel pour avoir les dernières mises à jour de sécurité.

    # Préparation : outils nécessaires pour ajouter le dépôt Docker
    sudo apt install ca-certificates curl gnupg -y
    
    # Ajout de la clé GPG (vérifie que les paquets viennent bien de Docker)
    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/debian/gpg | \
      sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg
    
    # Ajout du dépôt officiel Docker
    echo \
      "deb [arch=$(dpkg --print-architecture) \
      signed-by=/etc/apt/keyrings/docker.gpg] \
      https://download.docker.com/linux/debian \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    
    # Installation de Docker
    sudo apt install docker-ce docker-ce-cli containerd.io \
      docker-buildx-plugin docker-compose-plugin -y

    3. Utiliser Docker sans sudo

    Par défaut, seul root peut utiliser Docker. Pour éviter de taper sudo à chaque commande, j’ajoute mon utilisateur au groupe docker.

    sudo usermod -aG docker utilisateur

    Il faut ensuite se déconnecter puis se reconnecter en SSH pour que le changement prenne effet.

    4. Vérification de l’installation

    docker --version
    # Docker version 28.x.x
    
    docker compose version
    # Docker Compose version v2.x.x

    Si les deux commandes répondent, c’est que docker a bien était installé correctement.

    5. Pour aller plus loin

    # Voir les conteneurs actifs
    docker ps
    
    # Voir tous les conteneurs (même arrêtés)
    docker ps -a
    
    # Voir les images téléchargées
    docker images