Docker-Compose avec PostgreSQL + Adminer + Traefik (reverse proxy)

Installer un environnement docker-compose avec PostgreSQL, Adminer et Traefik.

Cet article montre comment mettre en place un docker-compose minimal qui réunit : PostgreSQL (base de données), Adminer (interface web de gestion) et surtout Traefik (reverse proxy moderne) pour exposer proprement vos services et préparer une montée en production sereine (domaines, HTTPS, middlewares).

Pourquoi Traefik ?

  • Découverte automatique : Traefik lit les labels Docker et crée les routes à la volée (pas de conf Nginx à maintenir).
    Dès qu’un service démarre avec des labels (traefik.enable=true, traefik.http.routers...), Traefik crée dynamiquement la route correspondante.
  • HTTPS automatique : Traefik gère Let’s Encrypt en natif via ACME.
    Il suffit de fournir l'email et le domaine (DOMAIN=example.com dans le .env), et Traefik se charge de :
    • demander le certificat SSL,
    • le stocker dans letsencrypt/acme.json,
    • le renouveler automatiquement avant expiration.
  • 👉 Résultat : tu as du HTTPS gratuit, renouvelé sans effort, là où avec Nginx tu devrais installer certbot, configurer les certificats et gérer les cron jobs.
    👉 En local : tu peux rester en HTTP (*.localhost), mais en prod tu as directement un HTTPS prêt à l’emploi.
  • Middlewares puissants : redirection HTTP→HTTPS, authentification basique, rate-limit, en-têtes de sécurité…
    • Traefik ne fait pas que du routage, il ajoute une couche de middlewares pour sécuriser et contrôler le trafic :
    • Redirection HTTP → HTTPS (force le chiffrement).
    • Authentification basique (protège un dashboard ou une app sensible).
    • Rate limiting (limiter le nombre de requêtes par IP, utile contre les abus).
    • Ajout d’en-têtes de sécurité (Strict-Transport-Security, X-Frame-Options, etc.).
  • Dashboard : Interface web (http://traefik.tondomaine) qui affiche en temps réel :
    • les routes configurées,
    • les services accessibles,
    • l’état des certificats SSL. Très utile pour déboguer rapidement.
  • Empilement de projets : un même proxy pour plusieurs applis (FastAPI, Django, etc.) grâce à un réseau partagé.

Prérequis

  • Docker et Docker Compose v2 installés.
  • Un nom de domaine si vous visez le HTTPS (ex. example.com). Pour un usage local, on peut rester en HTTP via *.localhost.

Variables d’environnement (.env)

Créez un fichier .env à la racine pour centraliser les secrets et le domaine.

# Nom de domaine principal (ex: exemple.com ou localhost en dev) DOMAIN=example.com # Adresse email pour l'enregistrement Let's Encrypt (obligatoire pour générer un certificat SSL) ACME_EMAIL=votre_email@example.com # Sécurité : utilisateur(s) autorisé(s) pour accéder au dashboard Traefik # Générer un mot de passe hashé avec : # htpasswd -nbB admin "motdepasse" | sed -e 's/$/$$/g' TRAEFIK_USERS=admin:$$2y$05$hashABRÉGÉDExxx... # Nom de la base POSTGRES_DB=appdb # Identifiants de connexion POSTGRES_USER=appuser POSTGRES_PASSWORD=mot_de_passe_sûr
👉 Explications :
  • DOMAIN : utilisé par tous les services pour construire les règles de routage (adminer.${DOMAIN}, traefik.${DOMAIN}, etc.).
  • ACME_EMAIL : permet à Let’s Encrypt de t’envoyer des alertes en cas de problème de certificat.
  • TRAEFIK_USERS : protège le dashboard Traefik avec une authentification basique.
  • POSTGRES_DB : nom de ta base par défaut.
  • POSTGRES_USER / POSTGRES_PASSWORD : utilisés à la fois par PostgreSQL et par Adminer pour se connecter.
Image Adminer

Le docker-compose.yml

Voici un fichier complet : Traefik (reverse proxy), PostgreSQL et Adminer, avec des labels pour le routage.

version: "3.9" services: traefik: image: traefik:v3.0 container_name: traefik command: - --api.dashboard=true - --api.insecure=false - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:443 - --providers.docker=true - --providers.docker.exposedbydefault=false # ACME / Let's Encrypt (HTTP challenge) - --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL} - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json - --certificatesresolvers.letsencrypt.acme.httpchallenge=true - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./letsencrypt:/letsencrypt networks: - web labels: - "traefik.enable=true" # Dashboard Traefik (protégé par auth basique) - "traefik.http.routers.traefik.rule=Host(traefik.${DOMAIN})" - "traefik.http.routers.traefik.entrypoints=web" - "traefik.http.routers.traefik.service=api@internal" - "traefik.http.middlewares.dashboard-auth.basicauth.users=${TRAEFIK_USERS}" - "traefik.http.routers.traefik.middlewares=dashboard-auth" db: image: postgres:16 container_name: postgres environment: - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} volumes: - dbdata:/var/lib/postgresql/data networks: - internal adminer: image: adminer:latest container_name: adminer depends_on: - db networks: - internal - web labels: - "traefik.enable=true" - "traefik.http.routers.adminer.rule=Host(adminer.${DOMAIN})" - "traefik.http.routers.adminer.entrypoints=web" # Port exposé par le conteneur Adminer - "traefik.http.services.adminer.loadbalancer.server.port=8080" # (Optionnel en prod HTTPS) # - "traefik.http.routers.adminer.tls=true" # - "traefik.http.routers.adminer.tls.certresolver=letsencrypt" volumes: dbdata: networks: web: name: web # réseau partagé pour que Traefik voie d'autres stacks internal: internal: true # réseau privé DB & services

Démarrage

docker compose up -d

Ensuite :

  • Accédez à http://traefik.<votre domaine> pour le dashboard (auth basique requise).
  • Accédez à http://adminer.<votre domaine> pour Adminer.

Connexion Adminer à PostgreSQL

  • Système : PostgreSQL
  • Serveur : db (nom du service Docker, car Adminer et la DB partagent le réseau internal)
  • Utilisateur : ${POSTGRES_USER}
  • Mot de passe : ${POSTGRES_PASSWORD}
  • Base : ${POSTGRES_DB}

Zoom sur Traefik : labels & routage

Le cœur de Traefik dans un contexte Docker, ce sont les labels posés sur chaque service.
Ils définissent et comment exposer le service.
Exemple minimal utilisé ci-dessus pour Adminer :

labels: - "traefik.enable=true"
- "traefik.http.routers.adminer.rule=Host(`adminer.${DOMAIN}`)"
- "traefik.http.routers.adminer.entrypoints=web"
- "traefik.http.services.adminer.loadbalancer.server.port=8080"

Avec le HTTPS automatique (Let’s Encrypt), on ajoute :

- "traefik.http.routers.adminer.tls=true"
- "traefik.http.routers.adminer.tls.certresolver=letsencrypt"

On peut aussi empiler des middlewares (auth, redirections, en-têtes de sécurité) :

- "traefik.http.middlewares.hsts.headers.stsSeconds=31536000"
- "traefik.http.middlewares.hsts.headers.stsIncludeSubdomains=true"
- "traefik.http.routers.adminer.middlewares=hsts"

Ajouter facilement une autre application (ex. FastAPI)

Une fois Traefik en place, exposer une nouvelle app revient à lui ajouter des labels :

app: image: tiangolo/uvicorn-gunicorn-fastapi:python3.11 environment:
- MODULE_NAME=main networks: - web labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`api.${DOMAIN}`)"
- "traefik.http.routers.app.entrypoints=web"
- "traefik.http.services.app.loadbalancer.server.port=80" # HTTPS en prod : #
- "traefik.http.routers.app.tls=true" #
- "traefik.http.routers.app.tls.certresolver=letsencrypt"

Bonnes pratiques & sécurité

  • Secrets : ne commitez pas .env ; utilisez un coffre de secrets ou des variables d’environnement CI/CD.
  • Traefik dashboard : gardez l’auth basique activée ou désactivez le dashboard en prod (--api.dashboard=false).
  • HTTPS : en production, activez websecure et Let’s Encrypt, et forcez la redirection HTTP→HTTPS.
  • Réseaux : isolez la base sur un réseau internal (comme ci-dessus), exposez uniquement via Traefik.
  • Mises à jour : mettez à jour régulièrement les images (postgres, adminer, traefik).

Dépannage rapide

  • 404 Traefik : vérifiez la règle Host() et le DNS/hosts. Assurez-vous que le service a traefik.enable=true.
  • Certificats : Let’s Encrypt nécessite un domaine public accessible en HTTP (port 80 ouvert).
  • Adminer n’atteint pas la DB : vérifiez que les services partagent bien le réseau internal et que l’hôte est db.

Remarque

Si tu veux que ton domaine (par exemple `adminer.localhost` ou autre) fonctionne en local, il faut ajouter une entrée dans ton fichier `hosts` afin qu’il pointe vers `127.0.0.1`.

1. Ouvre un terminal et édite le fichier :

sudo nano /etc/hosts

2. Ajoute :

127.0.0.1 adminer.localhost

3. Sauvegarde (`Ctrl+O` puis `Ctrl+X`).

à consulter sur : http://adminer.localhost

Conclusion

Traefik simplifie énormément l’exposition de vos services Docker : un reverse proxy orienté labels, prêt pour la production avec HTTPS automatique et des middlewares utiles.
Associé à PostgreSQL et Adminer, vous obtenez un socle solide pour vos projets data et web, que vous pourrez étendre en quelques lignes pour héberger d’autres applications.