Docs/ Infraestrutura/ Domínios Personalizados

Domínios personalizados

Associe seus próprios nomes de domínio a um app. O sh0 os roteia pelo Caddy e obtém o certificado HTTPS na primeira visita.

Adicionar um domínio

Um domínio é associado a um único app. A rota é enviada ao Caddy assim que o domínio é adicionado; o sh0 não espera pelo DNS.

  1. Abra o app no painel.
  2. Vá até a aba Domínios e SSL.
  3. Clique em Adicionar domínio e digite o nome em Nome do domínio, por exemplo api.example.com.
  4. Confirme com Adicionar domínio. A aba mostra então o registro DNS a criar (tipo A, valor: o IP do seu servidor).

Pela CLI, sh0 domains <app> add|list|remove faz o mesmo. remove aceita o nome ou o ID do domínio e pede confirmação, a menos que --yes seja informado:

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

Configuração de DNS

No seu provedor de DNS, aponte o nome para o IP público do servidor sh0 com um registro A. O painel mostra esse IP em Configuração de DNS, com um botão de cópia.

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

Para um subdomínio, um CNAME para outro nome que já resolve para o servidor funciona igualmente: o essencial é que a requisição chegue a esta máquina nas portas 80 e 443.

Warning
Para um domínio que você mesmo gerencia, o sh0 não consulta o DNS. O indicador DNS da lista não é uma verificação: o único sinal confiável é o Status SSL passar para Ativo.

Certificados HTTPS

O Caddy, proxy reverso gerenciado pelo sh0, obtém os certificados via ACME (Let's Encrypt, com ZeroSSL como alternativa). Não há nada a configurar, mas vale conhecer o funcionamento:

  • Sob demanda. O certificado é solicitado no primeiro handshake HTTPS para o nome, não quando o domínio é adicionado. Enquanto ninguém abrir https://api.example.com, o status fica Pendente.
  • Só para nomes roteados pelo sh0. Antes de emitir, o Caddy pergunta ao sh0 se alguma rota usa o nome; qualquer outro nome apresentado num handshake TLS é recusado, de modo que ninguém consegue fazer seu servidor pedir certificados para nomes arbitrários.
  • HTTP para HTTPS. O Caddy redireciona as requisições HTTP para HTTPS.
  • Renovação. O Caddy renova os certificados sozinho antes do vencimento.

A aba Domínios e SSL relê o status a cada 10 segundos enquanto houver um domínio pendente. Pela API, um domínio pendente traz o campo ssl_pending_reason com o motivo, por exemplo: “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.”

Atrás de uma CDN (proxy do Cloudflare)

Quando uma CDN termina o TLS na frente do seu servidor (Cloudflare com a nuvem laranja, por exemplo), a requisição de validação HTTP-01 para na CDN e o certificado pode nunca ser emitido. Há três saídas:

  • Somente DNS (nuvem cinza): o mais simples; o Caddy passa a atender os visitantes diretamente.
  • Validação DNS-01, domínio a domínio: o Caddy prova a posse do nome gravando um registro TXT pela API do Cloudflare em vez de responder por HTTP.
  • Um certificado próprio, como um certificado de origem do Cloudflare, enviado como descrito abaixo.

O DNS-01 exige um Caddy compilado com o módulo do Cloudflare (sudo sh0 install-dns-caddy e depois reiniciar o sh0) e um token de API do Cloudflare com Zone:DNS:Edit nas configurações do painel. Ele é ativado domínio a domínio, apenas pela API: o painel ainda não tem um controle para isso. Num servidor sem o módulo, a chamada é recusada (resposta real):

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."}}

O sh0 também recusa o DNS-01 quando não há token configurado e quando o domínio está fora da zona controlada pelo token: o desafio nunca poderia ser respondido ali. "challenge":"http-01" volta ao padrão.

Certificados próprios

Para usar um certificado da sua própria autoridade em vez do ACME, use a seção Certificados SSL da mesma aba:

  1. Ou Gerar CSR (a chave privada é criada e mantida no servidor) e enviar o CSR à sua autoridade, ou Enviar certificado com o certificado e a chave privada em PEM, mais a cadeia intermediária se a autoridade fornecer.
  2. Depois de enviar o certificado assinado, mude o domínio para Usar SSL personalizado.
  3. Usar SSL automático volta aos certificados automáticos. Excluir um certificado também devolve ao modo automático os domínios que o usavam. A renovação de um certificado próprio é responsabilidade sua.

Regras e limites

  • Sem curingas. *.example.com é recusado (“Domain labels must contain only alphanumeric characters and hyphens”). Adicione cada subdomínio explicitamente.
  • Worker não tem domínio. Um app do tipo worker não expõe porta HTTP; mude-o antes para o tipo web.
  • Um dono por nome. Um nome já associado a uma instância de armazenamento de arquivos é recusado.
  • Normalização. Os nomes têm os espaços removidos e são convertidos para minúsculas antes de serem gravados; cada rótulo tem de 1 a 63 caracteres: letras, dígitos e hífens.
  • Permissões. Adicionar ou remover um domínio, ou mudar sua validação, exige o papel developer no projeto do app.

Solução de problemas

Se o Status SSL continuar Pendente:

  • Leia ssl_pending_reason em GET /api/v1/apps/<id>/domains: ele indica a causa que o sh0 vê.
  • Verifique se o nome resolve para o IP público do servidor (dig +short).
  • Verifique se as portas 80 e 443 estão abertas em todos os firewalls na frente do servidor, inclusive o do seu provedor.
  • Abra o site uma vez por HTTPS: sem um primeiro handshake, nenhum certificado é solicitado.
  • Atrás de uma CDN, use uma das três saídas acima.
Terminal
$ dig +short api.example.com
$ curl -I http://api.example.com