Redirecionando HTTP para HTTPS no Nginx: Melhores Práticas

Configure um redirecionamento confiável de HTTP para HTTPS no Nginx usando um bloco dedicado na porta 80, evite loops de redirecionamento, escolha o código de redirecionamento correto e adicione HSTS quando estiver pronto.

Redirecionando HTTP para HTTPS no Nginx: Melhores Práticas

Redirecionar HTTP para HTTPS no Nginx garante que os visitantes usem a versão criptografada do seu site, mesmo que digitem a antiga URL http:// ou sigam um link desatualizado. Uma configuração de redirecionamento limpa melhora a segurança, evita URLs duplicadas e oferece aos usuários um ponto de entrada consistente.

A melhor abordagem geralmente é simples: mantenha a porta 80 aberta apenas o tempo suficiente para redirecionar o tráfego e sirva o site real na porta 443 com um certificado TLS válido.

Os detalhes importam porque os redirecionamentos são fáceis de fazer quase corretamente. Um redirecionamento que descarta o caminho quebra os favoritos. Um redirecionamento que preserva o nome de host errado pode criar URLs canônicas duplicadas. Um redirecionamento atrás de um balanceador de carga pode entrar em loop infinito se o Nginx não entender onde o TLS termina.

Pense no redirecionamento como parte da sua API pública. As pessoas colam links em chats, mecanismos de busca os rastreiam, sistemas de monitoramento os acessam e e-mails antigos os mantêm vivos por anos. Se o redirecionamento for estável, ninguém percebe. Se for descuidado, os usuários veem avisos de certificado, caminhos quebrados ou erros de muitos redirecionamentos antes mesmo de sua aplicação receber uma solicitação.

Por que os Redirecionamentos HTTPS são Importantes

O HTTPS protege o tráfego entre o navegador e seu servidor usando criptografia TLS. Sem ele, os dados podem ser inspecionados ou modificados por redes entre o usuário e seu site. Isso é importante para logins, formulários, cookies, áreas administrativas, APIs e até mesmo para navegação comum.

Os redirecionamentos também ajudam na consistência. Mecanismos de busca e usuários não devem ver http://exemplo.com/pagina e https://exemplo.com/pagina como dois destinos separados. Um redirecionamento permanente informa aos clientes que o HTTPS é a versão preferida.

O padrão Nginx comum é um bloco de servidor dedicado na porta 80:

server {
    listen 80;
    server_name exemplo.com www.exemplo.com;

    return 301 https://$host$request_uri;
}

Em seguida, seu bloco de servidor HTTPS lida com o site real:

server {
    listen 443 ssl http2;
    server_name exemplo.com www.exemplo.com;

    ssl_certificate /etc/letsencrypt/live/exemplo.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/exemplo.com/privkey.pem;

    root /var/www/exemplo.com;
    index index.html;
}

A diretiva return 301 é eficiente e clara. Ela instrui o Nginx a enviar um redirecionamento permanente sem processamento extra de localização. $request_uri preserva o caminho e a string de consulta, então /docs?pagina=2 se torna https://exemplo.com/docs?pagina=2.

Para uma configuração TLS completa, veja protegendo o Nginx com HTTPS.

Para a maioria dos sites, evite colocar lógica de aplicação no bloco da porta 80. Ele não deve servir arquivos estáticos, fazer proxy para a aplicação ou conter um grande conjunto de localizações. Mantenha-o simples:

server {
    listen 80;
    server_name exemplo.com www.exemplo.com;
    return 301 https://exemplo.com$request_uri;
}

Esse bloco pequeno é mais fácil de auditar e menos propenso a divergir da configuração HTTPS.

Escolhendo entre Redirecionamentos 301 e 302

Use 301 para um redirecionamento permanente de HTTP para HTTPS em um site de produção. Navegadores e mecanismos de busca entendem que a URL HTTPS deve substituir a URL HTTP.

Use 302 ou 307 apenas quando o redirecionamento for temporário. Por exemplo, você pode usar um redirecionamento temporário durante os testes antes que os certificados e nomes de host estejam finalizados. Quando o site HTTPS estiver pronto, mude para um redirecionamento permanente.

Tenha cuidado durante a configuração inicial. Os navegadores podem armazenar em cache redirecionamentos 301 de forma agressiva. Se você redirecionar acidentalmente para o nome de host errado, o navegador pode continuar usando o redirecionamento incorreto mesmo depois de corrigir o Nginx. Teste com curl, janelas privadas do navegador e nomes de host que não sejam de produção, quando possível.

Um fluxo de implantação prático se parece com isso:

  1. Confirme que o bloco do servidor HTTPS funciona diretamente.
  2. Confirme que o certificado corresponde a cada nome de host.
  3. Adicione o bloco do servidor de redirecionamento HTTP.
  4. Teste vários caminhos e strings de consulta.
  5. Altere redirecionamentos temporários para permanentes apenas quando o comportamento estiver correto.

Você também deve decidir sobre o nome de host canônico. Se ambos exemplo.com e www.exemplo.com funcionarem, escolha um como o nome de host público preferido. Caso contrário, os usuários podem saltar entre nomes de host ou os mecanismos de busca podem indexar ambos.

Por exemplo, para redirecionar todo o tráfego HTTP para o nome de host HTTPS sem www:

server {
    listen 80;
    server_name exemplo.com www.exemplo.com;

    return 301 https://exemplo.com$request_uri;
}

Isso é diferente de https://$host$request_uri, que preserva o host solicitado pelo usuário.

Você também pode dividir os redirecionamentos de nome de host dos redirecionamentos de esquema se quiser que o comportamento seja explícito:

server {
    listen 80;
    server_name www.exemplo.com;
    return 301 https://exemplo.com$request_uri;
}

server {
    listen 80;
    server_name exemplo.com;
    return 301 https://exemplo.com$request_uri;
}

Isso é mais verboso, mas torna o destino final óbvio. Em um site pequeno, qualquer estilo é aceitável. Em um site maior com muitos aliases, blocos de servidor explícitos podem reduzir a confusão durante alterações posteriores.

Evitando Loops de Redirecionamento e Problemas de Certificado

Loops de redirecionamento acontecem quando o Nginx, um balanceador de carga ou uma aplicação continua enviando uma solicitação de volta para uma URL que aciona outro redirecionamento. Isso é comum quando o TLS termina antes do Nginx, como em um balanceador de carga em nuvem ou CDN.

Em uma configuração simples de servidor único, o Nginx recebe HTTPS diretamente, então o redirecionamento é direto. Em uma cadeia de proxy, o Nginx pode receber HTTP simples do balanceador de carga, mesmo que o usuário tenha se conectado com HTTPS. Se sua aplicação então tentar forçar HTTPS com base no esquema de conexão local, isso pode causar um loop.

A correção depende da sua arquitetura. Geralmente, o balanceador de carga deve passar cabeçalhos como X-Forwarded-Proto, e a aplicação ou configuração do Nginx deve confiar neles apenas de endereços de proxy conhecidos.

Por exemplo, se o Nginx estiver atrás de um balanceador de carga confiável e receber apenas HTTP interno, você pode não querer que o Nginx redirecione cada solicitação HTTP local. Em vez disso, o balanceador de carga pode lidar com o redirecionamento público de HTTP para HTTPS, enquanto o Nginx atende ao tráfego da rede privada. Se o Nginx deve tomar a decisão, ele precisa de informações confiáveis de protocolo encaminhado do proxy à sua frente. Não confie em X-Forwarded-Proto de clientes arbitrários da internet.

Certifique-se também de que os certificados cubram cada nome de host redirecionado. Se um usuário visitar http://www.exemplo.com e você redirecionar para https://www.exemplo.com, o certificado deve ser válido para www.exemplo.com. Se você redirecionar tudo para https://exemplo.com, o certificado do site final deve cobrir exemplo.com.

Teste com:

curl -I http://exemplo.com/algum/caminho?x=1

Procure por:

HTTP/1.1 301 Moved Permanently
Location: https://exemplo.com/algum/caminho?x=1

Em seguida, teste a URL HTTPS:

curl -I https://exemplo.com/algum/caminho?x=1

A resposta HTTPS deve retornar o status real da página, não outro redirecionamento de volta para HTTP.

Teste também ambos os nomes de host, se ambos existirem:

curl -I http://www.exemplo.com/
curl -I https://www.exemplo.com/
curl -I http://exemplo.com/
curl -I https://exemplo.com/

Você está procurando uma cadeia curta e previsível. Um redirecionamento de HTTP para a URL HTTPS canônica é bom. Múltiplos saltos, como HTTP não-www para HTTPS não-www para HTTPS www e vice-versa, são um sinal de que o Nginx, o aplicativo, as regras da CDN ou o encaminhamento em nível de DNS estão em conflito.

Você pode inspecionar toda a cadeia com:

curl -IL http://www.exemplo.com/algum/caminho

A flag -L segue os redirecionamentos. Em uma configuração limpa, a saída deve mostrar a resposta HTTP inicial e, em seguida, a resposta HTTPS final. Se você vir três ou quatro cabeçalhos Location, simplifique as regras até que haja uma rota clara para a URL canônica.

HSTS e Outras Melhores Práticas

Depois que sua configuração HTTPS estiver estável, você pode considerar o HTTP Strict Transport Security, geralmente chamado de HSTS. O HSTS informa aos navegadores para usar HTTPS automaticamente em visitas futuras.

Um cabeçalho comum se parece com isso:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Não adicione isso casualmente. Se você incluir subdomínios, cada subdomínio deve suportar HTTPS. Se você quebrar o HTTPS posteriormente, os navegadores que viram o cabeçalho HSTS podem se recusar a acessar a versão HTTP. Comece com um max-age mais curto durante os testes e aumente-o quando estiver confiante.

Outras melhores práticas:

  • Mantenha o bloco da porta 80 simples.
  • Preserve caminhos e strings de consulta, a menos que tenha um motivo para não fazê-lo.
  • Escolha um nome de host canônico.
  • Teste redirecionamentos com curl, não apenas com um navegador.
  • Renove certificados automaticamente e monitore falhas de renovação.
  • Mantenha a lógica de redirecionamento no Nginx quando possível, em vez de duplicá-la no aplicativo.

Regras de redirecionamento simples são mais fáceis de raciocinar e menos propensas a quebrar durante alterações posteriores no site.

Erros Comuns

O erro mais comum é usar rewrite para um redirecionamento simples:

rewrite ^ https://exemplo.com$request_uri permanent;

Isso pode funcionar, mas return 301 ... é mais claro e evita processamento extra de reescrita. Use rewrite quando você realmente precisar de correspondência de padrões, não para um redirecionamento básico de esquema.

Outro erro é redirecionar para $server_name sem entender o que ele contém. $host vem do cabeçalho de host da solicitação, enquanto $server_name é baseado no nome do servidor Nginx correspondente. Para redirecionamentos canônicos, um nome de host literal é geralmente a opção menos surpreendente:

return 301 https://exemplo.com$request_uri;

Você também deve evitar redirecionar caminhos de desafio ACME HTTP se suas ferramentas de certificado precisarem deles na porta 80. Muitas configurações do Let's Encrypt lidam com isso automaticamente, mas configurações personalizadas podem precisar de uma exceção:

location /.well-known/acme-challenge/ {
    root /var/www/letsencrypt;
}

location / {
    return 301 https://exemplo.com$request_uri;
}

Adicione essa exceção apenas se seu cliente de certificado a usar. Se seus certificados forem renovados por meio de validação DNS ou um servidor temporário gerenciado por ferramentas, mantenha o bloco de redirecionamento simples.

Um Padrão de Implantação Seguro

Para um site de produção, faça a alteração em etapas:

  1. Confirme que o bloco do servidor HTTPS atende o site corretamente.
  2. Confirme que a renovação do certificado funciona ou é monitorada.
  3. Adicione um redirecionamento temporário na porta 80 se você ainda estiver testando nomes de host.
  4. Teste URLs comuns com curl -I e curl -IL.
  5. Mude para 301 assim que o destino do redirecionamento estiver final.
  6. Aguarde antes de ativar o HSTS de longa duração.

Esse período de espera é útil. Ele dá tempo para detectar subdomínios esquecidos, URLs de webhook antigas, links http:// codificados ou uma regra de CDN que não era visível em sua primeira máquina de teste.

Também mantenha o monitoramento em mente. Se sua verificação de disponibilidade ainda aponta para http://exemplo.com, decida se ela deve esperar um 301 ou seguir redirecionamentos e verificar a página HTTPS final. Ambos podem ser válidos, mas o monitor deve corresponder ao comportamento que você realmente deseja.

Exemplo: Site Estático e Proxy Reverso

Para um site estático, o bloco HTTPS pode ser apenas uma raiz de documentos:

server {
    listen 443 ssl http2;
    server_name exemplo.com;

    ssl_certificate /etc/letsencrypt/live/exemplo.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/exemplo.com/privkey.pem;

    root /var/www/exemplo.com;
    index index.html;
}

Para uma aplicação atrás do Nginx, o bloco de redirecionamento permanece o mesmo, mas o bloco HTTPS faz proxy do tráfego:

server {
    listen 443 ssl http2;
    server_name exemplo.com;

    ssl_certificate /etc/letsencrypt/live/exemplo.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/exemplo.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

O ponto importante é a separação. A porta 80 decide para onde o navegador deve ir. A porta 443 atende o site. Misturar essas tarefas torna o comportamento do redirecionamento mais difícil de raciocinar, especialmente quando outro proxy ou CDN é adicionado posteriormente.

Após editar, sempre execute:

sudo nginx -t
sudo systemctl reload nginx

Se o teste falhar, não recarregue. Corrija o erro de sintaxe primeiro e teste novamente.

Uma verificação final vale a pena ser feita de fora do servidor, não apenas via SSH no host. Um firewall, CDN ou balanceador de carga pode alterar o que os usuários reais veem. Execute as mesmas verificações curl -I do seu laptop, de um local de monitoramento ou de uma instância de nuvem temporária. Se o resultado externo for diferente do localhost, o problema de redirecionamento provavelmente está na camada de rede à frente do Nginx, não no próprio bloco do servidor. Verifique isso antes de reescrever uma configuração funcional.

Quando Obter Ajuda

Obtenha ajuda de um engenheiro DevOps se seu site estiver atrás de uma CDN, balanceador de carga em nuvem, ingress do Kubernetes ou vários proxies reversos. Redirecionamentos HTTPS em infraestrutura em camadas dependem de onde o TLS termina e em quais cabeçalhos são confiáveis.

Você também deve pedir ajuda antes de ativar o HSTS de longo prazo em muitos subdomínios. Uma configuração errada pode bloquear o acesso dos usuários a serviços que não estão prontos para HTTPS.

Redirecionar HTTP para HTTPS no Nginx é uma pequena mudança de configuração com um grande impacto na segurança. Use um bloco de redirecionamento dedicado na porta 80, preserve o URI da solicitação, verifique os certificados e teste loops antes de considerar concluído.