Aller au contenu

Architecture VPS Docker

Une architecture multi-stack Docker désigne une organisation où plusieurs groupes de services (stacks) coexistent sur un même serveur, chacun défini par son propre fichier docker-compose.yaml. Chaque stack est autonome mais peut communiquer avec les autres via un réseau Docker partagé.

Cette infrastructure tourne sur un VPS Hostinger KVM 4 :

  • 16 GB RAM / 4 vCPU / Debian 13
  • 7 stacks Docker interconnectées
  • 1 reverse proxy (Caddy) comme point d’entrée HTTP
  • 1 tunnel SSH dédié comme point d’entrée hors HTTP (pour TimeTrackr)
StackServicesFonctionRAM ordre de grandeur
security-stackCaddy, CrowdSec, TrivyReverse proxy + WAF + scanner CVE~500 MB
n8n-stackN8N main + 5 workers, PostgreSQL, RedisAutomatisation queue mode~2 GB
ai-stackQdrant, CLI Ollama, Claude Redis, MCP Gateway, N8N MCPIA, vecteurs, MCP~4 GB
odoo-stackOdoo 18, PostgreSQLERP (DB guig_db)~1.5 GB
monitoring-stackPrometheus, Grafana, Alertmanager, OTEL Collector, exportersObservabilité + telemetry~1.5 GB
notify-stackDIUN, ntfyNotifications + détection updates~200 MB
timetrackr-stackPostgreSQL 17 (tunnel SSH dédié)Buffer time tracking~150 MB

Réseaux isolés

réseau webproxy (partagé)

Points d'entrée

HTTPS / HTTP3

SSH key + ForceCommand

forward 5433

Internet

TimeTrackr.exe · poste utilisateur

Caddy · :80, :443, :443/udp

sshd · :22 · timetrackr-tunnel restreint

security-stack · CrowdSec, Trivy

n8n-stack · N8N main + 5 workers

ai-stack · CLI Ollama, MCP Gateway

odoo-stack · :8069, DB guig_db

monitoring-stack · Grafana, Prometheus

notify-stack · ntfy

mcp-backend · gateway ↔ n8n-mcp

ai-internal · Qdrant, Claude Redis

timetrackr-internal · PG 17

Trois familles de réseaux Docker se côtoient :

  • webproxy — bridge partagé, point de routage de Caddy.
  • Réseaux internes par stack (n8n-internal, odoo-internal, monitoring, ai-internal) — communication intra-stack.
  • Réseaux isolés (mcp-backend, timetrackr-internal, crowdsec-internal) — surfaces réduites pour les composants sensibles (MCP gateway, base TimeTrackr, API CrowdSec).

  1. Simplicité opérationnelle — Kubernetes introduit etcd, control plane, ingress controllers, inadaptés à un serveur unique. Docker Compose démarre une stack en une commande.

  2. Contraintes de ressources — L’overhead Kubernetes (2-4 GB RAM pour le control plane) consommerait 15-25 % du VPS. Docker Compose n’a pas cet overhead.

  3. Pas de besoin de scaling horizontal — Pas d’auto-scaling, pas de répartition multi-nœuds. Le scaling vertical (plus de RAM/CPU) suffit.

  4. Courbe d’apprentissage — Compose est maîtrisé, Kubernetes serait un investissement disproportionné pour ce cas d’usage.

ProblèmeSolution
Isolation des pannesUne stack défaillante n’impacte pas les autres
Déploiement indépendantMise à jour d’un service sans redémarrer tout le système
Versions divergentesChaque stack gère ses dépendances (PG 15 pour N8N/Odoo, PG 17 pour TimeTrackr)
Sécurité par segmentationSurfaces minimales : MCP backend isolé, base TimeTrackr hors webproxy
ObservabilitéStack dédiée qui scrape toutes les autres

stacks_vps/
├── security-stack/ # Caddy + CrowdSec + Trivy
├── n8n-stack/ # N8N en mode queue, 5 workers
├── ai-stack/ # Qdrant + CLI Ollama + MCP Gateway + N8N MCP
├── odoo-stack/ # Odoo 18 ERP (DB guig_db)
├── monitoring-stack/ # Prometheus + Grafana + OTEL
├── notify-stack/ # DIUN + ntfy
├── timetrackr-stack/ # PostgreSQL 17 + tunnel SSH (hors webproxy)
├── workflows/ # Documentation des workflows N8N
├── docs-external/ # 📦 Submodule : docs CLI externes
├── n8n-exports/ # 📦 Submodule : exports workflows N8N
├── blog/ # 📦 Submodule : ce blog (Astro)
└── scripts/ # deploy-all.sh, backup-databases.sh, …

Toutes les stacks HTTP se branchent sur le réseau externe webproxy :

networks:
webproxy:
external: true

Ce réseau bridge permet à Caddy d’atteindre n’importe quel container par son nom (n8n:5678, odoo:8069, grafana:3000, ntfy:80, …).

Exception : timetrackr-stack ne touche pas webproxy. Sa base PostgreSQL est exposée uniquement sur 127.0.0.1:5433, et l’accès passe par un user SSH dédié (timetrackr-tunnel) avec ForceCommand /bin/false et PermitOpen localhost:5433. Voir TimeTrackr Stack pour le détail.

Fenêtre de terminal
# Créer le réseau partagé (une seule fois)
docker network create webproxy
# Démarrer toutes les stacks
./scripts/deploy-all.sh start
# Status
./scripts/deploy-all.sh status
# Logs d'une stack
./scripts/deploy-all.sh logs n8n-stack
# Redémarrer
./scripts/deploy-all.sh restart odoo-stack
# Pull + redémarrage
./scripts/deploy-all.sh pull
  1. security-stack — Le reverse proxy doit être prêt avant les autres pour terminer les handshakes TLS.
  2. monitoring-stack — Pour capter l’historique de scrape dès le boot des autres.
  3. ai-stack, n8n-stack, odoo-stack, notify-stack — Dans n’importe quel ordre.
  4. timetrackr-stack — Indépendante (n’a pas besoin de webproxy).

Le script scripts/backup-databases.sh (cron quotidien 03:00) produit :

  • pg_dump de la base N8N (n8n).
  • pg_dump de la base Odoo (guig_db) + archive du filestore.
  • pg_dump de la base TimeTrackr (timetrackr_db).
  • Sauvegarde de la N8N_ENCRYPTION_KEY (sans elle, les credentials sont irrécupérables).

Rotation locale (7 jours) et push GDrive (30 jours) via rclone. Échec → alerte au Notification Hub.


LimiteImpactMitigation
Serveur uniqueSPOF physiqueBackups quotidiens GDrive + monitoring + alertes
Pas de HA nativeDowntime au pull/restartFenêtres planifiées, self-restart pattern pour n8n-stack
Scaling vertical uniquementPlafond matériel KVM 4Migration vers KVM 8 ou multi-nœuds possible
AI stack la plus gourmande~4 GB sur 16 disponiblesSub-processus CLI court-vivants, pas de modèle local

Si je dois répliquer ce setup pour un autre client :

  • Les stacks deviennent des modèles, packagés en namespaces Kubernetes (ou Compose templates).
  • Helm charts pour les variations par client (DB names, secrets, domaines).

Si les besoins IA explosent :

  • L’ai-stack devient externalisable vers un cloud GPU (l’interface API Ollama-compatible facilite le swap).
  • Garder Qdrant local pour la latence RAG, pousser CLI Ollama vers un host dédié.

Si 16 GB devient insuffisant :

  • Upgrade KVM 8 (32 GB) — solution la plus simple.
  • Ou déporter monitoring + notify sur un second serveur, le webproxy peut s’étendre en overlay multi-host.

Si la souveraineté SSH doit être renforcée :

  • Migration du tunnel TimeTrackr vers WireGuard (wg.guigpap.com).
  • Permet d’ouvrir d’autres services privés (admin Postgres, Redis interne) sans multiplier les bouncers SSH.

  • Glossaire — Définitions des termes techniques