Docker: Roteamento HTTPS

Como gerir o roteamento HTTP e a encriptação TLS (HTTPS) nos seus contentores Docker

Bem-vindo à documentação da Stackhero

A Stackhero disponibiliza uma plataforma Docker cloud CaaS (Containers as a Service) pronta a usar, concebida para implementações de contentores rápidas e fiáveis:

  • Implemente em produção com um simples docker-compose up. Não é necessária qualquer configuração adicional: basta iniciar os seus contentores.
  • Escolha o seu próprio nome de domínio, automaticamente protegido com HTTPS (por exemplo: https://api.sua-empresa.com, https://www.sua-empresa.com ou https://backoffice.sua-empresa.com).
  • Beneficie de elevado desempenho e segurança robusta numa infraestrutura privada e dedicada.
  • Aplique atualizações com um clique para uma manutenção simples e sem esforço.

Pode ter os seus contentores em produção em cerca de cinco minutos. A Stackhero gere a infraestrutura, as atualizações e a segurança por si, para que se possa focar na entrega das suas aplicações. Saiba mais sobre alojamento cloud Docker CaaS.

Cada instância do Stackhero para Docker inclui um servidor Traefik dedicado e pré-configurado que gere o tráfego HTTP e o encripta automaticamente usando certificados TLS. Esta configuração simplificada torna o roteamento simples e eficiente. Por exemplo:

  • Enviar tráfego de https://www.my-company.com (com ou sem o prefixo www) para o seu contentor frontend.
  • Roteie https://www.my-company.com/documentations para o seu contentor documentations.
  • Direcione https://api.my-project.io para o seu contentor api.

Pode gerir um número ilimitado de domínios com criação e renovação automática de certificados TLS. O melhor de tudo é que pode configurar tudo isto com apenas três linhas!

Em todos os exemplos de configuração seguintes, terá de substituir <XXXXXX>.stackhero-network.com pelo nome de domínio da sua instância Stackhero para Docker.

Abaixo está um exemplo básico de um ficheiro docker-compose.yml:

services:
  test:
    image: nginx
    labels:
      - "traefik.enable=true" # Ativar Traefik para rotear tráfego para este contentor
      - "traefik.http.routers.test.rule=Host(`<XXXXXX>.stackhero-network.com`)" # Definir o host
      - "traefik.http.routers.test.tls.certresolver=letsencrypt" # Usar 'letsencrypt' como o resolvedor de certificado TLS

Neste exemplo, um contentor chamado test funciona com a imagem Nginx. A configuração chave é fornecida na secção de labels. Apenas precisa de copiar estas linhas para o seu ficheiro docker-compose.yml e substituir <XXXXXX>.stackhero-network.com pelo seu domínio de serviço.

Pode implantar o contentor usando:

docker context use <XXXXXX>.stackhero-network.com
docker-compose up

Após o arranque do contentor, visite https://<XXXXXX>.stackhero-network.com/ para ver a página "Welcome to nginx!".

Página de boas-vindas do NginxPágina de boas-vindas do Nginx

Se não vir a página de boas-vindas do Nginx, verifique o painel de controlo do Traefik para possíveis erros!

Com esta configuração, os pedidos HTTP enviados para <XXXXXX>.stackhero-network.com são roteados para o seu contentor test e o Traefik cria e gere automaticamente os certificados TLS para HTTPS.

No exemplo anterior, utilizámos o domínio padrão <XXXXXX>.stackhero-network.com. Na prática, provavelmente usará os seus próprios domínios de empresa ou projeto, como www.my-company.com ou api.my-project.io. A secção abaixo explica como configurar domínios personalizados.

Neste exemplo, irá configurar o domínio api.my-project.io. Substitua my-project.io por um domínio que possua e api pelo subdomínio desejado.

Primeiro, atualize as definições DNS do seu domínio para que api.my-project.io aponte para o seu domínio <XXXXXX>.stackhero-network.com.

  1. Inicie sessão no seu fornecedor de domínio e aceda à sua configuração DNS.
  2. Crie uma nova entrada chamada api (ou outro subdomínio à sua escolha), defina o seu tipo como CNAME e defina o seu destino como <XXXXXX>.stackhero-network.com.

Exemplo de configuração DNS na interface DNS do CloudflareExemplo de configuração DNS na interface DNS do Cloudflare

Uma vez configurado o DNS, pode validá-lo executando:

host api.my-project.io

Deverá ver uma resposta semelhante a:

api.my-project.io is an alias for <XXXXXX>.stackhero-network.com

A propagação DNS pode demorar até 24 horas, dependendo do seu fornecedor. Se o comando host não devolver a resposta esperada, aguarde e tente novamente mais tarde.

Em seguida, atualize o seu ficheiro docker-compose.yml com a seguinte configuração:

services:
  api:
    image: traefik/whoami
    hostname: api
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=Host(`api.my-project.io`)" # Adicione o seu domínio aqui
      - "traefik.http.services.api.loadbalancer.server.port=<PORT>" # Substitua "<PORT>" pelo porto em que a sua API está a ouvir
      - "traefik.http.routers.api.tls.certresolver=letsencrypt"

Não se esqueça de substituir api.my-project.io pelo seu domínio real no label Traefik Host.

Implante o seu contentor com:

docker-compose up -d

Depois visite https://api.my-project.io. Deverá ver uma página de texto exibindo o nome do host do seu contentor api.

Prova de que o Traefik está a gerir o nosso tráfego HTTP com encriptação TLS para o nosso novo domínioProva de que o Traefik está a gerir o nosso tráfego HTTP com encriptação TLS para o nosso novo domínio

Na primeira criação do contentor, os certificados TLS podem demorar alguns segundos a serem gerados. Se encontrar um erro TLS, aguarde alguns segundos e atualize a página para permitir tempo para os certificados serem gerados.

Parabéns, configurou agora o seu primeiro domínio personalizado!

Ao definir um URL de site como my-company.com, é uma boa ideia configurar também um subdomínio "www". Isto garante que os utilizadores que se conectam via www.my-company.com são redirecionados para o seu site principal e ajuda a evitar problemas de conteúdo duplicado.

No exemplo abaixo, tanto my-company.com como www.my-company.com são geridos. Os utilizadores que acedem a www.my-company.com são redirecionados para my-company.com:

services:
  frontend:
    image: traefik/whoami
    hostname: frontend
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frontend.rule=Host(`my-company.com`) || Host(`www.my-company.com`)" # Adicione ambos os domínios aqui
      - "traefik.http.services.frontend.loadbalancer.server.port=<PORT>" # Substitua "<PORT>" pelo porto em que o seu frontend está a ouvir
      - "traefik.http.routers.frontend.tls.certresolver=letsencrypt"

      # Redirecionar 'www.my-company.com' para 'my-company.com':
      - 'traefik.http.routers.frontend.middlewares=redirect-www'
      - "traefik.http.middlewares.redirect-www.redirectregex.regex=^https://www.my-company.com/(.*)"
      - "traefik.http.middlewares.redirect-www.redirectregex.replacement=https://my-company.com/$${1}"
      - "traefik.http.middlewares.redirect-www.redirectregex.permanent=true"

Suponha que tem um contentor dedicado ao seu site de documentação. Pode querer rotear https://my-company.com/docs para este contentor enquanto envia outros pedidos, como https://my-company.com/, para o seu contentor frontend. O exemplo abaixo mostra como isto é feito:

services:
  documentations:
    image: traefik/whoami
    hostname: documentations
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.documentations.rule=Host(`my-company.com`) && PathPrefix(`/docs`)" # Defina o prefixo do caminho aqui
      - "traefik.http.services.documentations.loadbalancer.server.port=<PORT>" # Substitua "<PORT>" pelo porto em que o seu contentor de documentação está a ouvir
      - "traefik.http.routers.documentations.tls.certresolver=letsencrypt"

  frontend:
    image: traefik/whoami
    hostname: frontend
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frontend.rule=Host(`my-company.com`) || Host(`www.my-company.com`)"
      - "traefik.http.services.frontend.loadbalancer.server.port=<PORT>" # Substitua "<PORT>" pelo porto em que o seu frontend está a ouvir
      - "traefik.http.routers.frontend.tls.certresolver=letsencrypt"

      # Redirecionar 'www.my-company.com' para 'my-company.com':
      - 'traefik.http.routers.frontend.middlewares=redirect-www'
      - "traefik.http.middlewares.redirect-www.redirectregex.regex=^https://www.my-company.com/(.*)"
      - "traefik.http.middlewares.redirect-www.redirectregex.replacement=https://my-company.com/$${1}"
      - "traefik.http.middlewares.redirect-www.redirectregex.permanent=true"

Agora, visitar https://my-company.com/docs (ou qualquer subcaminho como https://my-company.com/docs/something) exibirá conteúdo do contentor documentations. Outros caminhos, por exemplo https://my-company.com/help, serão servidos pelo contentor frontend.

Por padrão, o Traefik conecta-se à primeira porta exposta do contentor. Em alguns casos, pode precisar de especificar uma porta particular. O exemplo abaixo demonstra como definir uma porta personalizada:

services:
  frontend:
    image: traefik/whoami
    hostname: frontend
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frontend.rule=Host(`my-company.com`)"
      - "traefik.http.routers.frontend.tls.certresolver=letsencrypt"

      # Roteie o tráfego de 'https://my-company.com' para o contentor 'frontend' na porta 80
      - "traefik.http.services.frontend.loadbalancer.server.port=80"

Ao definir um contentor no seu ficheiro docker-compose.yml, alguns campos são importantes para melhor consistência e facilidade de gestão. Considere usar a seguinte configuração recomendada:

services:
  <CONTAINER_NAME>:
    image: traefik/whoami
    hostname: <CONTAINER_NAME>
    container_name: <CONTAINER_NAME>
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.<CONTAINER_NAME>.rule=Host(`my-company.com`)"
      - "traefik.http.routers.<CONTAINER_NAME>.tls.certresolver=letsencrypt"

Basta substituir <CONTAINER_NAME> pelo nome desejado para o seu contentor, por exemplo frontend.

Ao criar um subdomínio, o Let's Encrypt segue as RFC 952 e 1123, que permitem apenas caracteres no conjunto [a-zA-Z0-9-].

Embora os underscores ('_') sejam permitidos nos nomes de registos DNS, não são aceitáveis em nomes de host. Como resultado, o Let's Encrypt rejeita subdomínios como "my_subdomain.example.com" e exibe o erro "Domain name contains an invalid character".

Para resolver este problema, basta remover quaisquer underscores dos seus subdomínios.