01 - L'architecture : VPS, Docker Compose et Caddy
Ce que tu vas apprendre
- L'architecture complète d'un déploiement Docker Compose en production
- Comment Caddy gere le reverse proxy et l'auto-SSL
- La structure du docker-compose.yml et du Caddyfile
- Pourquoi Caddy plutot que Nginx ou Traefik
Prerequisites
- 00 - Introduction : pourquoi automatiser
Vue d'ensemble
Voici l'architecture du projet qui tourne sur paltemps.fr. Un VPS OVH sous Ubuntu 25.04, avec Docker Compose qui orchestre 4 conteneurs :
Internet
|
[ VPS OVH ]
Ubuntu 25.04
|
[ Docker Compose ]
/ | \ \
/ | \ \
[ Caddy ] [ App ] [ Mail ] [ Chrome ]
:80/:443 :3000 :25/:587 :9222
|
Reverse Proxy
Auto-SSL (Let's Encrypt)
|
+-----------+-----------+-----------+
| | | |
paltemps.fr blog. deck. benchmark.
paltemps.fr paltemps.fr paltemps.fr
Caddy est le point d'entree. Il recoit toutes les requêtes HTTP/HTTPS, regarde le header Host, et redirige vers le bon service. L'app Bun gere l'API et sert le frontend. Le serveur mail (docker-mailserver) gere les emails du domaine. Chrome headless fait du scraping de pages web.
Le docker-compose.yml
Voici la structure réelle (simplifiee pour la lisibilité) :
yamlservices:
app:
build: .
restart: unless-stopped
environment:
- NODE_ENV=production
- PORT=3000
volumes:
- ./data:/app/data
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
mailserver:
image: ghcr.io/docker-mailserver/docker-mailserver:latest
restart: unless-stopped
hostname: inbox.paltemps.fr
ports:
- "25:25"
- "587:587"
- "993:993"
volumes:
- ./docker-data/dms/mail-data:/var/mail
- ./docker-data/dms/config:/tmp/docker-mailserver
chrome:
image: ghcr.io/browserless/chromium
restart: unless-stopped
environment:
- MAX_CONCURRENT_SESSIONS=2
volumes:
caddy_data:
caddy_config:
Chaque service a restart: unless-stopped. Si le VPS reboot, tout redemarre automatiquement. Le volume caddy_data persiste les certificats SSL entre les redemarrages, sinon tu te fais rate-limit par Let's Encrypt.
Le Caddyfile
C'est la que la magie opéré. Caddy fait le reverse proxy ET gere les certificats SSL automatiquement :
paltemps.fr {
reverse_proxy app:3000
}
blog.paltemps.fr {
reverse_proxy app:3000
}
deck.paltemps.fr {
reverse_proxy app:3000
}
benchmark.paltemps.fr {
reverse_proxy app:3000
}
inbox.paltemps.fr {
reverse_proxy app:3000
}
C'est tout. Pas de blocs server, pas de listen 443 ssl, pas de ssl_certificate. Tu mets le nom de domaine, Caddy obtient un certificat Let's Encrypt, configure HTTPS, redirige HTTP vers HTTPS. Automatiquement. Au premier démarrage, ca prend environ 30 secondes pour provisionner tous les certificats.
Le Dockerfile (multi-stage)
L'application utilise un Dockerfile multi-stage pour garder l'image legere :
dockerfileFROM oven/bun:1 AS base
WORKDIR /app
FROM base AS install
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile --production
FROM base AS build
COPY --from=install /app/node_modules ./node_modules
COPY . .
RUN bun run build
FROM base AS release
COPY --from=install /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY --from=build /app/public ./public
COPY package.json .
USER bun
EXPOSE 3000
CMD ["bun", "run", "dist/index.js"]
Quatre étapes : base, install des dépendances, build du frontend, image finale. L'image de production ne contient que le strict nécessaire : les node_modules de prod, le code compile et les assets statiques. Pas de devDependencies, pas de sources TypeScript.
Pourquoi Caddy et pas Nginx
J'ai une opinion assez tranchee la-dessus : pour 90% des projets web, Caddy est un meilleur choix que Nginx.
Avec Nginx, tu dois configurer les certificats SSL toi-meme. En général, tu installes Certbot, tu configures un cron pour le renouvellement, tu ecris un bloc server avec les chemins vers les certificats. Ca marche, mais c'est 30 lignes de config en plus et un point de failure supplementaire.
Avec Caddy, tu ecris le nom de domaine. C'est fini. HTTPS est actif. Le certificat se renouvelle tout seul. Zero config supplementaire.
Et Traefik ? Traefik est plus puissant que Caddy, avec une découverte automatique des services Docker via des labels. Mais cette puissance a un coût : la configuration est plus verbeuse, la courbe d'apprentissage est plus raide, et pour un projet avec 4 ou 5 services, c'est clairement overkill. J'ai utilise Traefik sur des projets plus gros et il fait bien son travail, mais ici Caddy gagne par sa simplicité.
Les DNS
Pour que tout fonctionne, il faut que tes enregistrements DNS pointent vers l'IP de ton VPS. Dans le panel OVH (ou ton registrar), tu ajoutes :
paltemps.fr A 203.0.113.42
blog.paltemps.fr A 203.0.113.42
deck.paltemps.fr A 203.0.113.42
inbox.paltemps.fr A 203.0.113.42
benchmark.paltemps.fr A 203.0.113.42
Ou plus malin, un wildcard :
*.paltemps.fr A 203.0.113.42
Comme ca, chaque nouveau sous-domaine est automatiquement redirige vers ton VPS. Tu n'ajoutes que l'entree dans le Caddyfile.
La suite
L'architecture est en place. Dans le prochain article, on installe GitLab Runner sur le VPS pour que tout ca se deploie automatiquement a chaque push.
Navigation : Precedent : 00 - Introduction | Suivant : 02 - Installer GitLab Runner
Sources
- Caddy documentation par Caddy
- Docker Compose documentation par Docker
- docker-mailserver documentation par docker-mailserver
- Bun Docker images par Oven
Retrouve d'autres articles techniques sur paltemps.fr.