Finalisation d’une infrastructure Nomad : DNS wildcard avec Hetzner, certificats SSL automatiques via Traefik/Let’s Encrypt, et déploiement d’apps en quelques lignes.
Contexte
Suite au premier article sur la migration vers Nomad, il manquait la brique essentielle : exposer les services en HTTPS avec des certificats valides. Cette partie couvre la mise en place complète du DNS et des certificats SSL.
Architecture finale
Internet
│
┌────────▼────────┐
│ Hetzner DNS │
│ *.lab.sylvainp.dev
└────────┬────────┘
│
┌─────────────┴─────────────┐
│ │
┌───────▼───────┐ ┌────────▼────────┐
│ dataplatform │ │ ddim │
│ 157.180.26.24 │ │ 95.216.158.226 │
│ │ │ │
│ ┌─────────┐ │ │ MySQL, Neo4j │
│ │ Traefik │ │ │ (workloads) │
│ │ :80/443 │ │ └─────────────────┘
│ └────┬────┘ │
│ │ │
│ ┌────▼────┐ │
│ │ Nomad │ │
│ │ 25+ jobs│ │
│ └─────────┘ │
└───────────────┘
1. DNS Wildcard avec Hetzner
Hetzner fournit un service DNS gratuit. Un seul enregistrement wildcard suffit pour router tous les sous-domaines vers Traefik.
Configuration
# Lister les zones
hcloud zone list
# Créer le wildcard
hcloud zone rrset create \
--name "*.lab" \
--type A \
--record "157.180.26.24" \
sylvainp.devRésultat : tout *.lab.sylvainp.dev pointe vers le serveur principal.
Vérification
dig grafana.lab.sylvainp.dev @hydrogen.ns.hetzner.com
# Résultat attendu :
# grafana.lab.sylvainp.dev. 300 IN A 157.180.26.242. Traefik avec Let’s Encrypt
Traefik gère automatiquement l’obtention et le renouvellement des certificats via le challenge HTTP-01.
Job Nomad Traefik (extrait)
job "traefik" {
datacenters = ["hel1"]
type = "service"
group "ingress" {
# Volume pour persister les certificats
volume "traefik-certs" {
type = "host"
source = "traefik-certs"
read_only = false
}
network {
port "http" { static = 80 }
port "https" { static = 443 }
}
task "traefik" {
driver = "docker"
volume_mount {
volume = "traefik-certs"
destination = "/letsencrypt"
read_only = false
}
config {
image = "traefik:v3.2"
ports = ["http", "https"]
args = [
"--api.insecure=true",
"--entrypoints.web.address=:80",
"--entrypoints.websecure.address=:443",
"--entrypoints.web.http.redirections.entryPoint.to=websecure",
"--providers.consulCatalog=true",
"--providers.consulCatalog.endpoint=172.17.0.1:8500",
"--certificatesresolvers.letsencrypt.acme.email=admin@example.com",
"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json",
"--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web",
]
}
}
}
}
Points clés
| Élément | Rôle |
|---|---|
httpChallenge |
Let’s Encrypt valide via HTTP (port 80) |
/letsencrypt/acme.json |
Stockage persistant des certificats |
providers.consulCatalog |
Auto-découverte des services Nomad |
| Redirect HTTP → HTTPS | Forcé au niveau entrypoint |
3. Persistance des certificats
Sans persistance, chaque redémarrage de Traefik déclenche une nouvelle demande de certificat. Let’s Encrypt limite à 50 certificats/domaine/semaine.
Configuration du host volume
Sur le serveur Nomad :
# Créer le répertoire
mkdir -p /opt/nomad/volumes/traefik-certs
chmod 700 /opt/nomad/volumes/traefik-certsDans /etc/nomad.d/client.hcl :
client {
host_volume "traefik-certs" {
path = "/opt/nomad/volumes/traefik-certs"
read_only = false
}
}
Vérification
# Certificats stockés
cat /opt/nomad/volumes/traefik-certs/acme.json | python3 -m json.tool | grep mainVue Storage & Backup
Le dashboard inclut une vue dédiée au stockage avec les priorités de backup par service :

- Volumes CSI (Hetzner) : survivent à la perte de VM, snapshots automatiques
- Volumes Host : backup manuel requis, chemins dans
/opt/nomad/volumes/ - Priorités : critique (bases de données), haute (InfluxDB, Registry), moyenne (Grafana, certificats)
4. Déployer une app en HTTPS
Avec cette infrastructure, déployer une nouvelle app avec HTTPS automatique prend 3 étapes.
Étape 1 : Build et push l’image
cd /path/to/myapp
# Build
docker build -t 157.180.26.24:5000/myapp:latest .
# Push vers le registry privé
docker push 157.180.26.24:5000/myapp:latestÉtape 3 : Déployer
export NOMAD_ADDR=http://157.180.26.24:4646
nomad job run myapp.nomad.hclC’est tout. L’app est accessible en HTTPS avec un certificat valide.
curl -I https://myapp.lab.sylvainp.dev
# HTTP/2 200
# Certificate: Let's Encrypt5. Protection BasicAuth (optionnel)
Pour protéger une app par mot de passe :
# Générer le hash
htpasswd -nbB admin "secret123"
# admin:$2y$05$...Ajouter dans les tags du service :
tags = [
# ... tags existants ...
"traefik.http.routers.myapp.middlewares=myapp-auth",
"traefik.http.middlewares.myapp-auth.basicauth.users=admin:$$2y$$05$$...",
]
Services exposés
| Service | URL | Certificat |
|---|---|---|
| Dashboard | dashboard.lab.sylvainp.dev | Let’s Encrypt |
| Grafana | grafana.lab.sylvainp.dev | Let’s Encrypt |
| Airflow | airflow.lab.sylvainp.dev | Let’s Encrypt |
| Keycloak | keycloak.lab.sylvainp.dev | Let’s Encrypt |
Troubleshooting
Certificat “TRAEFIK DEFAULT CERT”
Le certificat Let’s Encrypt n’est pas encore émis. Vérifier :
# Logs Traefik
nomad alloc logs <traefik-alloc-id>
# Vérifier que le port 80 est accessible
curl http://myapp.lab.sylvainp.devDNS ne résout pas
# Vérifier via nameservers Hetzner
dig myapp.lab.sylvainp.dev @hydrogen.ns.hetzner.comVérifier un certificat
echo | openssl s_client -connect 157.180.26.24:443 \
-servername myapp.lab.sylvainp.dev 2>/dev/null | \
openssl x509 -noout -issuer -datesRécapitulatif
| Composant | Solution |
|---|---|
| DNS | Hetzner DNS (wildcard) |
| Reverse Proxy | Traefik v3 |
| Certificats | Let’s Encrypt (auto) |
| Orchestration | HashiCorp Nomad |
| Discovery | HashiCorp Consul |
Cette stack permet de déployer n’importe quelle app conteneurisée en HTTPS en moins de 5 minutes, sans configuration DNS manuelle pour chaque service.
Hetzner DNS · Traefik · Let’s Encrypt · Nomad