iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
iducationducation
IndexArticlesFormationsProfilOutilsBibliothech
N°014 — 2026
Navigation
01Index02Articles03Formations04Profil05Outils06Bibliothech
N°014 — 2026
Formations
TypeScript · Avancé

OpenCaddyHost

Construire un dashboard Nuxt 4 pour piloter Caddy via son Admin API — authentification JWT, reverse proxy CRUD, import/export, et déploiement Docker Compose.

Nuxt 4Vue 3TypeScriptPiniaCaddyDocker
GitHub
01Setup et configuration02L'API Admin de Caddy03Server routes Nuxt 404Authentification JWT05Client Caddy et gestion des proxies06Interface et composants Vue07Déploiement Docker Compose
Chapitre 7·25 min

Déploiement Docker Compose

OpenCaddyHost se déploie avec un seul docker compose up qui lance Caddy et le dashboard ensemble, sur le même réseau Docker.

docker-compose.yml

docker-compose.yml
version: '3.8'
 
services:
  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "2020:2019"      # Admin API exposée sur le port 2020 de l'hôte
    volumes:
      - caddy_config:/config
      - caddy_data:/data
    networks:
      - caddy_network
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:2019/config/"]
      interval: 30s
      timeout: 10s
      retries: 3
 
  dashboard:
    build: .
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - JWT_SECRET=${JWT_SECRET}
      - ADMIN_USERNAME=${ADMIN_USERNAME}
      - ADMIN_PASSWORD=${ADMIN_PASSWORD}
      - CADDY_ADMIN_URL=http://caddy:2019   # réseau Docker interne
      - NODE_ENV=production
    depends_on:
      caddy:
        condition: service_healthy          # attend que Caddy soit prêt
    volumes:
      - ./logs:/app/logs
    networks:
      - caddy_network
    healthcheck:
      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/api/health"]
      start_period: 60s
      interval: 30s
 
volumes:
  caddy_config:
  caddy_data:
 
networks:
  caddy_network:
    driver: bridge

CADDY_ADMIN_URL=http://caddy:2019 — le dashboard parle à Caddy via le nom de service Docker (caddy), pas via localhost. Sur le réseau bridge Docker, chaque service est résolvable par son nom.

Dockerfile

Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
 
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=builder /app/.output ./output
ENV HOST=0.0.0.0
ENV PORT=3000
EXPOSE 3000
CMD ["node", "output/server/index.mjs"]

Build multi-étapes : l'image finale ne contient que .output/ — pas de node_modules, pas de sources. Image finale ~150MB au lieu de ~800MB.

Déploiement initial

Terminal
# Copier et configurer l'environnement
cp .env.example .env
nano .env   # changer JWT_SECRET, ADMIN_PASSWORD
 
# Build et démarrage
docker compose up -d --build
 
# Vérifier que les deux services tournent
docker compose ps
 
# Logs en temps réel
docker compose logs -f dashboard
NAME          STATUS
caddy         Up (healthy)
dashboard     Up (healthy)

Vérification

Terminal
# Dashboard accessible
curl http://localhost:3000/api/health
 
# Admin API Caddy accessible depuis l'hôte
curl http://localhost:2020/config/
 
# Admin API depuis le conteneur dashboard (via réseau Docker)
docker compose exec dashboard wget -qO- http://caddy:2019/config/

Sécurisation en production

1. Ne pas exposer le port 2020 publiquement

Le port 2020 (Admin API Caddy) ne doit être accessible qu'en local ou via VPN. Sur un VPS, bloquer ce port avec UFW :

Terminal
ufw deny 2020

Et retirer le mapping de port dans docker-compose.yml si le dashboard et Caddy sont sur la même machine :

caddy:
  # ports:
  #   - "2020:2019"   ← supprimer en production si non nécessaire

2. Caddy devant le dashboard

En production, on place Caddy comme reverse proxy devant le dashboard lui-même. Le dashboard répond en HTTPS automatiquement, Caddy gère Let's Encrypt :

Caddyfile
dashboard.example.com {
  reverse_proxy localhost:3000
}

Mais puisque la config Caddy est gérée via l'Admin API JSON, l'équivalent est d'envoyer cette route au démarrage :

Terminal
curl -X POST http://localhost:2020/load \
  -H "Content-Type: application/json" \
  -d '{
    "apps": {
      "http": {
        "servers": {
          "srv0": {
            "listen": [":443"],
            "routes": [{
              "@id": "proxy-dashboard",
              "match": [{"host": ["dashboard.example.com"]}],
              "handle": [{"handler": "reverse_proxy", "upstreams": [{"dial": "localhost:3000"}]}]
            }]
          }
        }
      }
    }
  }'

3. Changer les credentials par défaut

.env
JWT_SECRET=$(openssl rand -base64 48)
ADMIN_USERNAME=mon-username
ADMIN_PASSWORD=mot-de-passe-fort-et-unique

Ne jamais pousser .env sur GitHub — il est dans .gitignore par défaut.

Mise à jour

Terminal
git pull
docker compose up -d --build dashboard   # rebuild uniquement le dashboard, Caddy reste intact

--build dashboard rebuild seulement le service dashboard. Caddy continue de tourner sans interruption — les proxies configurés restent actifs.

Sauvegarde de la configuration Caddy

La config Caddy est persistée dans le volume caddy_config. Pour la sauvegarder :

Terminal
# Export via l'API
curl http://localhost:2020/config/ > caddy-backup-$(date +%Y%m%d).json
 
# Restore
curl -X POST http://localhost:2020/load \
  -H "Content-Type: application/json" \
  -d @caddy-backup-20260616.json

Ou directement via le dashboard : page "Import / Export" → bouton "Télécharger".

Précédent
Interface et composants Vue

Développeur fullstack passionné. J'apprends en construisant et je documente tout — front, back, outils. Le code s'apprend mieux en public.

Naviguer

IndexTous les articlesFormationsProfilOutilsBibliothech

Ailleurs

GitHub RSS

Newsletter

Les articles, libs et découvertes. Une fois par semaine, pas plus.

© 2026 William LoreeConçu & codé à la main