Docs/ Infrastructure/ Domaines personnalisés

Domaines personnalisés

Rattachez vos propres noms de domaine à une application. sh0 les route par Caddy et obtient le certificat HTTPS à la première visite.

Ajouter un domaine

Un domaine est rattaché à une seule application. La route est transmise à Caddy dès l'ajout ; sh0 n'attend pas le DNS.

  1. Ouvrez l'application dans le tableau de bord.
  2. Allez dans l'onglet Domaines & SSL.
  3. Cliquez sur Ajouter un domaine et saisissez le nom dans Nom de domaine, par exemple api.example.com.
  4. Validez avec Ajouter un domaine. L'onglet affiche alors l'enregistrement DNS à créer (type A, valeur : l'IP de votre serveur).

En ligne de commande, sh0 domains <app> add|list|remove fait la même chose. remove accepte le nom ou l'identifiant du domaine et demande confirmation, sauf avec --yes :

Terminal
$ sh0 domains my-api add api.example.com
[ok] Added domain api.example.com to my-api

$ sh0 domains my-api remove api.example.com --yes
[ok] Removed api.example.com from my-api

Configuration DNS

Chez votre fournisseur DNS, faites pointer le nom vers l'adresse IP publique du serveur sh0 avec un enregistrement A. Le tableau de bord affiche cette IP sous Configuration DNS, avec un bouton de copie.

DNS
api.example.com.   A   <your server IP>

Pour un sous-domaine, un CNAME vers un autre nom qui résout déjà vers le serveur convient tout autant : l'essentiel est que la requête atteigne cette machine sur les ports 80 et 443.

Warning
Pour un domaine que vous gérez vous-même, sh0 n'interroge pas le DNS. L'indicateur DNS de la liste n'est pas une vérification : le seul signal fiable est le passage du Statut SSL à Actif.

Certificats HTTPS

Caddy, le proxy inverse piloté par sh0, obtient les certificats par ACME (Let's Encrypt, avec ZeroSSL en secours). Rien à configurer, mais le fonctionnement mérite d'être connu :

  • À la demande. Le certificat est demandé à la première poignée de main HTTPS pour ce nom, pas à l'ajout du domaine. Tant que personne n'a ouvert https://api.example.com, le statut reste En attente.
  • Uniquement pour les noms routés par sh0. Avant toute émission, Caddy demande à sh0 si une route porte ce nom ; tout autre nom présenté lors d'une poignée de main TLS est refusé, si bien que personne ne peut faire demander à votre serveur des certificats pour des noms arbitraires.
  • HTTP vers HTTPS. Caddy redirige les requêtes HTTP vers HTTPS.
  • Renouvellement. Caddy renouvelle les certificats de lui-même avant leur expiration.

L'onglet Domaines & SSL relit le statut toutes les 10 secondes tant qu'un domaine est en attente. Par l'API, un domaine en attente porte un champ ssl_pending_reason qui en donne la raison, par exemple : « No TLS handshake for this name has reached this server yet: certificates are issued on demand at the first visit. Check that DNS points here, then open the site once over HTTPS. »

Derrière un CDN (proxy Cloudflare)

Quand un CDN termine le TLS devant votre serveur (Cloudflare avec le nuage orange, par exemple), la requête de validation HTTP-01 s'arrête au CDN et le certificat peut ne jamais être émis. Trois issues :

  • DNS uniquement (nuage gris) : le plus simple ; Caddy parle alors directement aux visiteurs.
  • La validation DNS-01, domaine par domaine : Caddy prouve la possession du nom en écrivant un enregistrement TXT par l'API Cloudflare au lieu de répondre en HTTP.
  • Un certificat personnalisé, par exemple un certificat d'origine Cloudflare, importé comme décrit plus bas.

DNS-01 exige un Caddy compilé avec le module Cloudflare (sudo sh0 install-dns-caddy, puis redémarrer sh0) et un jeton d'API Cloudflare doté de Zone:DNS:Edit dans les paramètres du tableau de bord. Il s'active domaine par domaine, par l'API seulement : le tableau de bord n'a pas encore de commande pour cela. Sur un serveur sans le module, l'appel est refusé (réponse réelle) :

Terminal
$ sudo sh0 install-dns-caddy        # then restart sh0
$ curl -X PUT https://panel.example.com/api/v1/apps/<app-id>/domains/<domain-id>/tls-challenge \
    -H "Authorization: Bearer $SH0_TOKEN" -H "Content-Type: application/json" \
    -d '{"challenge":"dns-01"}'
{"error":{"code":"VALIDATION_ERROR","message":"This server's Caddy carries no DNS provider module, so DNS-01 cannot be used. Run `sh0 install-dns-caddy` and restart sh0; until then this domain would keep HTTP-01 and the setting would be a lie."}}

sh0 refuse aussi DNS-01 quand aucun jeton n'est configuré, et quand le domaine est hors de la zone que contrôle le jeton : le défi n'y aurait jamais de réponse. "challenge":"http-01" revient au mode par défaut.

Certificats personnalisés

Pour utiliser un certificat de votre propre autorité plutôt qu'ACME, passez par la section Certificats SSL du même onglet :

  1. Soit Générer un CSR (la clé privée est créée et conservée sur le serveur) puis soumettre le CSR à votre autorité, soit Importer un certificat avec le certificat et sa clé privée au format PEM, plus la chaîne intermédiaire si votre autorité la fournit.
  2. Une fois le certificat signé importé, basculez le domaine sur Utiliser un SSL personnalisé.
  3. Utiliser le SSL automatique revient aux certificats automatiques. Supprimer un certificat ramène aussi en mode automatique les domaines qui l'utilisaient. Le renouvellement d'un certificat personnalisé reste à votre charge.

Règles et limites

  • Pas de domaine générique. *.example.com est refusé (« Domain labels must contain only alphanumeric characters and hyphens »). Ajoutez chaque sous-domaine explicitement.
  • Un worker ne peut pas avoir de domaine. Une application de type worker n'expose aucun port HTTP ; passez-la d'abord en type web.
  • Un seul propriétaire par nom. Un nom déjà rattaché à une instance de stockage de fichiers est refusé.
  • Normalisation. Les noms sont débarrassés des espaces et mis en minuscules avant d'être enregistrés ; chaque label compte de 1 à 63 caractères : lettres, chiffres et tirets.
  • Droits. Ajouter ou retirer un domaine, ou changer sa validation, exige le rôle developer sur le projet de l'application.

Dépannage

Si le Statut SSL reste En attente :

  • Lisez ssl_pending_reason dans GET /api/v1/apps/<id>/domains : il nomme la cause que voit sh0.
  • Vérifiez que le nom résout vers l'IP publique du serveur (dig +short).
  • Vérifiez que les ports 80 et 443 sont ouverts dans chaque pare-feu devant le serveur, y compris celui de votre hébergeur.
  • Ouvrez le site une fois en HTTPS : sans première poignée de main, aucun certificat n'est demandé.
  • Derrière un CDN, utilisez l'une des trois issues ci-dessus.
Terminal
$ dig +short api.example.com
$ curl -I http://api.example.com