Aller au contenu
Sylvain Joffraud l4w
Retour

Cert wildcard Let’s Encrypt : DNS-01 OVH & catch-all Apache

Nouveau projet projet-a-staging.dev.example.com sur srv-a — Coolify route via Traefik, le DNS résout grâce au wildcard *.dev de la zone. Mais le navigateur hurle : openssl s_client ... | openssl x509 -subject renvoie CN = cloud.example.com, le cert de NextCloud.

Aucun vhost n’a ce ServerName, Apache tombe sur le default. Et chaque projet Coolify exigerait son cert HTTP-01 + vhost. Pas tenable.

Piège 1 : *-staging.dev.example.com n’est pas un wildcard

La RFC 4592 limite * à un label entier :

Et LE n’émet de wildcard que via DNS-01 (HTTP-01 valide un nom exact).

Piège 2 : signer une requête OVH

Pour le consumer_key OVH au scope minimal, trois pièges :

  1. La key reste pendingValidation tant qu’on n’a pas cliqué la validationUrl.
  2. La signature n’est pas HMAC-SHA1 : c’est '$1$' + SHA1(AS+CK+METHOD+URL+BODY+TIMESTAMP), $1$ littéral.
  3. Le timestamp vient de /1.0/auth/time, pas de l’horloge locale, sinon 403.

Piège 2b : /domain/zone/domain/zone/ dans les ACL OVH

Token scopé à example.com, certbot répond 403 ... /domain/zone/.. Le plugin liste les zones via /domain/zone/ (trailing slash). En curl direct, /domain/zone → 200 mais /domain/zone/ → 403.

OVH traite /domain/zone et /domain/zone/ comme deux ACL distinctes (et GET /domain/zone/* ne couvre pas la chaîne vide). Il faut les deux règles :

{"method":"GET","path":"/domain/zone"},
{"method":"GET","path":"/domain/zone/"},

Piège 3 : Apache ServerAlias *.foo ne casse rien

Apache priorise toujours un ServerName exact sur un ServerAlias wildcard. Migration sans downtime : on active le catch-all, les sous-domaines sans vhost dédié prennent le cert wildcard, ceux qui en ont un restent servis par lui. Puis on retire chaque vhost dédié et son cert HTTP-01 orphelin.

Au final :

certbot certonly --dns-ovh --dns-ovh-credentials /etc/letsencrypt/ovh.ini \
  --dns-ovh-propagation-seconds 60 \
  -d '*.dev.example.com' -d 'dev.example.com' --cert-name dev.example.com
<VirtualHost *:443>
    ServerName dev.example.com
    ServerAlias *.dev.example.com
    SSLCertificateFile /etc/letsencrypt/live/dev.example.com/fullchain.pem
    ProxyPass / https://127.0.0.1:8443/   # Traefik
</VirtualHost>

Chaque projet Coolify <n>.dev.example.com a alors HTTPS valide sans toucher Apache.

TL;DR

Questions fréquentes

Pourquoi mon sous-domaine renvoie le mauvais certificat SSL (CN d’un autre site) en HTTPS ?
Si aucun vhost n’a de ServerName correspondant, Apache sert le vhost par défaut et donc son certificat, d’où un CN qui ne correspond pas au domaine demandé. Vérifiez avec openssl s_client -connect host:443 | openssl x509 -subject : un CN inattendu confirme que vous tombez sur le default vhost. La solution est un vhost catch-all avec un certificat wildcard.
Peut-on obtenir un certificat Let’s Encrypt avec un wildcard partiel comme *-staging.example.com ?
Non. La RFC 4592 limite le * à un label entier : *.dev.example.com est valide, mais *-staging.dev.example.com est invalide au DNS comme côté Let’s Encrypt. De plus, Let’s Encrypt n’émet de wildcard que via le challenge DNS-01 ; HTTP-01 ne valide qu’un nom exact.
Pourquoi certbot avec le plugin dns-ovh renvoie 403 sur /domain/zone alors que mon token est scopé sur le domaine ?
OVH traite /domain/zone et /domain/zone/ (avec trailing slash) comme deux ACL distinctes, et GET /domain/zone/* ne couvre pas la chaîne vide. Le plugin certbot liste les zones via /domain/zone/. Il faut donc ajouter les deux règles au consumer_key : {method:GET, path:/domain/zone} et {method:GET, path:/domain/zone/}.
Comment servir tous les sous-domaines avec un seul certificat wildcard sans casser les vhosts existants sous Apache ?
Apache priorise toujours un ServerName exact sur un ServerAlias wildcard, donc activer un vhost catch-all avec ServerAlias *.dev.example.com ne casse rien. Les sous-domaines sans vhost dédié prennent le cert wildcard, ceux qui en ont un restent servis par lui ; on peut ensuite retirer chaque vhost dédié et son cert HTTP-01 orphelin, sans downtime.

Partager cet article :

Article précédent
Migrer Plausible vers Coolify v4 : 5 pièges en 30 min
Article suivant
OVH DNS via Terraform : refresh zone auto, MX préservés