Como Ativar HTTPS no Django Localhost com Certificado SSL e TLS: Guia Completo com OpenSSL, runserver_plus, Uvicorn e Segurança de Cookies, CSRF e React

Published on: 2026-03-23
Post image
pt https-django-localhost django-https-local configurar-ssl-django-desenvolvimento certificado-ssl-localhost-django tls-django-local django-runserver-https runserver_plus-django-ssl django-extensions-https criar-certificado-openssl-localhost openssl

Habilitar HTTPS no ambiente local de desenvolvimento com Django transforma testes de segurança e integrações modernas em uma rotina natural. A navegação cifrada permite validar cookies seguros, políticas de navegador e fluxos de autenticação que exigem canal protegido. Essa configuração evita surpresas ao migrar para produção, onde HTTPS é obrigatório. A proposta a seguir descreve passo a passo como criar certificados, ajustar o Django e executar o servidor local com criptografia ativa.

O percurso inclui conceitos essenciais, comandos completos e alternativas para diferentes cenários. Há atenção especial a certificados autoassinados e certificados confiáveis pelo sistema, além de detalhes sobre cookies, CSRF e cabeçalhos de segurança. Também surge uma integração opcional com um frontend em React, útil em projetos com duas camadas. O resultado final é um ambiente local fiel ao comportamento de produção, mantendo praticidade no dia a dia.

O que muda ao ativar HTTPS no localhost

Antes do HTTPS local, o desenvolvimento ocorria com HTTP simples e sem criptografia, tornando invisíveis problemas de cookies seguros e políticas de navegador. Nesse formato anterior, sinalizadores como Secure em cookies eram ignorados, e fluxos que exigem canal cifrado, como OAuth, ficavam incompletos. Com HTTPS local, o tráfego passa a ser cifrado usando TLS, aproximando o ambiente de produção e ativando proteções do navegador. Essa mudança revela erros de configuração mais cedo e aumenta a confiabilidade dos testes.

O comportamento de bibliotecas e navegadores também se alinha às exigências atuais. Recursos como Service Workers e APIs modernas exigem contexto seguro e passam a funcionar no desenvolvimento. Políticas de SameSite e CSRF se comportam como em produção, permitindo validar fluxos de sessão reais. A experiência geral fica mais previsível, reduzindo ajustes de última hora perto do lançamento.

Conceitos essenciais: TLS, certificado e chave privada

TLS é o protocolo que cifra o tráfego entre cliente e servidor, garantindo confidencialidade e integridade. O certificado digital identifica o servidor e carrega a chave pública, enquanto a chave privada correspondente permanece protegida no host. Um certificado autoassinado é emitido pelo próprio desenvolvedor, útil em ambiente local, porém inicialmente não confiável para o navegador. A confiança surge ao adicionar o certificado à loja de certificados do sistema operacional.

Em certificados modernos, o campo Subject Alternative Name (SAN) define os nomes válidos do host, como localhost e seus IPs. Sem SAN, navegadores rejeitam o certificado mesmo com um Common Name preenchido. Para uso local, SAN precisa incluir localhost, 127.0.0.1 e, preferencialmente, ::1 para IPv6. Essa atenção ao SAN elimina o erro “CER_INVALID” e ativa o cadeado de segurança no navegador.

Gerando certificados com OpenSSL (incluindo SAN)

Para criar um par de chaves e um certificado autoassinado com SAN adequado, um comando direto do OpenSSL resolve o cenário mais comum. O exemplo a seguir cria uma pasta dedicada, gera o arquivo de chave e o certificado por 825 dias, e inclui SAN para localhost e IPs. O tamanho de chave de 4096 bits é robusto, e a opção de não usar senha facilita o uso com servidores locais. As respostas interativas do OpenSSL podem ser substituídas por parâmetros não interativos, como abaixo.

# criar pasta para certificados
mkdir -p ~/certs
cd ~/certs

# gerar certificado autoassinado com SAN (requer OpenSSL >= 1.1.1)
openssl req -x509 -newkey rsa:4096 -days 825 -nodes \
  -keyout key.pem -out cert.pem \
  -subj "/CN=localhost" \
  -addext "subjectAltName = DNS:localhost,IP:127.0.0.1,IP:::1"

Em versões antigas do OpenSSL sem suporte a -addext, um arquivo de configuração alternativo atende ao SAN. O bloco a seguir cria um arquivo simples e chama o OpenSSL com a extensão correta. Essa abordagem impede o erro de compatibilidade e mantém o certificado dentro das exigências atuais dos navegadores. O resultado é funcionalmente equivalente ao comando anterior.

# criar arquivo san.cnf com a extensão SAN
cat > san.cnf <<'EOF'
subjectAltName=DNS:localhost,IP:127.0.0.1,IP:::1
EOF

# gerar chave e CSR, depois assinar o certificado com SAN
openssl req -newkey rsa:4096 -nodes -keyout key.pem -out req.csr -subj "/CN=localhost"
openssl x509 -req -in req.csr -signkey key.pem -days 825 -out cert.pem -extfile san.cnf

Tornando o certificado confiável no sistema operacional

Para evitar avisos do navegador sobre autoridade não confiável, o certificado raiz precisa ser adicionado à loja de confiança do sistema. Em ambientes Linux baseados em Debian e Ubuntu, o diretório de autoridades locais e o utilitário de atualização resolvem o processo. Em distribuições baseadas em Red Hat, há diretórios e comandos equivalentes. Em macOS e Windows, comandos nativos também realizam a importação.

# Debian/Ubuntu
sudo mkdir -p /usr/local/share/ca-certificates/localhost
sudo cp ~/certs/cert.pem /usr/local/share/ca-certificates/localhost/localhost.crt
sudo update-ca-certificates

# Fedora/RHEL/CentOS
sudo cp ~/certs/cert.pem /etc/pki/ca-trust/source/anchors/localhost.crt
sudo update-ca-trust

# macOS (adiciona como raiz confiável no chaveiro do usuário)
security add-trusted-cert -d -r trustRoot -k ~/Library/Keychains/login.keychain-db ~/certs/cert.pem

# Windows (converter para DER e importar na loja Raiz Confiável)
openssl x509 -in ~/certs/cert.pem -outform der -out ~/certs/cert.cer
certutil -addstore -f "Root" "%USERPROFILE%\certs\cert.cer"

Após importar, o navegador tende a aceitar o certificado para localhost sem alertas de autoridade. Caso múltiplos navegadores sejam usados, alguns mantêm caches próprios e podem exigir reinicialização. Hosts adicionais além de localhost exigem novos SANs e novo certificado. Em ambientes corporativos, políticas de dispositivo podem bloquear a importação e pedem credenciais administrativas.

Preparando o projeto Django: configurações de segurança

Com o certificado pronto, configurações de segurança do Django ativam o contexto HTTPS e protegem cookies e formulários. Os parâmetros a seguir garantem redirecionamento para HTTPS, cookies apenas via canal seguro e tokens CSRF alinhados ao navegador. Hosts e origens confiáveis também são definidos para evitar restrições indevidas durante os testes. Em desenvolvimento, HSTS não é recomendado para impedir bloqueio acidental de HTTP local.

# settings.py (trecho seguro para desenvolvimento com HTTPS local)

DEBUG = True  # manter em desenvolvimento
ALLOWED_HOSTS = ['localhost', '127.0.0.1', '[::1]']

# Cookies e CSRF sobre HTTPS
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
CSRF_TRUSTED_ORIGINS = ['https://localhost:8000']

# Redirecionar HTTP para HTTPS durante os testes locais
SECURE_SSL_REDIRECT = True

# Não aplicar HSTS no ambiente local
SECURE_HSTS_SECONDS = 0
SECURE_HSTS_INCLUDE_SUBDOMAINS = False
SECURE_HSTS_PRELOAD = False

# Se houver proxy TLS terminando a conexão antes do Django, habilitar:
# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Ao usar portas diferentes ou domínios alternativos, CSRF_TRUSTED_ORIGINS precisa refletir exatamente o esquema e host. Em ambientes com proxy reverso, a diretiva SECURE_PROXY_SSL_HEADER instrui o Django a respeitar o cabeçalho do protocolo. Esses ajustes eliminam redirecionamentos em loop e falsos negativos de CSRF. A lista de hosts aceita acessos locais tradicionais por IPv4 e IPv6.

Executando o servidor de desenvolvimento com SSL via runserver_plus

O servidor padrão do Django não oferece TLS nativo, então uma extensão prática habilita HTTPS com um único comando. A combinação de django-extensions e Werkzeug provê o runserver_plus, que aceita arquivos de certificado e chave. A biblioteca pyOpenSSL complementa a pilha para o handshake TLS. A instalação e o registro do app tornam o comando disponível.

# instalar dependências
pip install "django-extensions>=3.2" "werkzeug>=3" "pyOpenSSL>=24"

# adicionar à lista de apps do Django
# settings.py:
# INSTALLED_APPS = [
#     ...,
#     'django_extensions',
# ]

Com os pacotes instalados e o app registrado, o servidor com HTTPS entra em operação informando os caminhos do certificado. O comando seguinte parte da pasta do manage.py e usa as chaves geradas no diretório padrão. A porta pode ser ajustada conforme a necessidade do projeto. O endereço explícito evita dúvidas sobre a interface de rede.

# executar o servidor de desenvolvimento com HTTPS
python manage.py runserver_plus --cert-file ~/certs/cert.pem --key-file ~/certs/key.pem localhost:8000

Certificado automático gerado pelo Werkzeug

Em cenários rápidos, um certificado autoassinado pode ser criado automaticamente pelo Werkzeug. Nessa opção, não há necessidade de gerar manualmente os arquivos com o OpenSSL. O comando gera pares temporários nomeados e os usa na sessão atual. É uma forma ágil de habilitar HTTPS local para testes imediatos.

# gerar e usar certificado automaticamente
python manage.py runserver_plus --key-file selftest-key --cert-file selftest-cert localhost:8000

Essa alternativa agiliza a experimentação, mas não cria confiança no sistema operacional por padrão. O navegador pode exibir alertas de autoridade até a importação manual apropriada na loja de certificados. Para integração com frontends e múltiplas ferramentas, certificados persistentes costumam ser mais práticos. Em rotinas diárias, manter arquivos fixos em ~/certs costuma simplificar scripts.

Alternativas sem runserver_plus: ASGI com Uvicorn ou Daphne

Alguns times preferem usar um servidor ASGI direto com TLS, evitando extensões no servidor de desenvolvimento do Django. O Uvicorn aceita parâmetros de certificado e chave, bastando apontar para o aplicativo ASGI do projeto. O Daphne também oferece suporte nativo a TLS com opções específicas na linha de comando. Essas opções se aproximam do stack usado em produção com ASGI.

# Uvicorn (certificado e chave)
pip install "uvicorn[standard]>=0.29"
uvicorn config.asgi:application --host localhost --port 8000 \
  --ssl-certfile ~/certs/cert.pem --ssl-keyfile ~/certs/key.pem

# Daphne (endereço com endpoint SSL)
pip install "daphne>=4"
daphne -e ssl:8000:privateKey=~/certs/key.pem:certKey=~/certs/cert.pem config.asgi:application

Ao migrar para ASGI, a compatibilidade com middlewares e websockets passa a ser testada com mais realismo. Em projetos que dependem de long-lived connections, essa abordagem oferece benefícios claros. Os mesmos certificados locais funcionam nesses servidores, mantendo a configuração coesa. A escolha depende do fluxo de trabalho e do alinhamento com o ambiente produtivo.

Depuração e modos de execução durante o desenvolvimento

Servidores com depuradores embutidos podem conflitar com depuradores de IDE, exigindo executar em modo de execução simples. Quando isso ocorre, pontos de interrupção podem não disparar e a pilha interativa do servidor assume a inspeção. Alternativas incluem desativar o depurador do servidor ou iniciar o app com servidores ASGI compatíveis com a IDE. Testar as combinações resolve a melhor ergonomia para o time.

Em alguns fluxos, variáveis de ambiente e argumentos do servidor definem o comportamento do depurador. Rodar o processo sem hot reloader da ferramenta do servidor pode estabilizar a sessão de debug. A execução com HTTPS permanece funcional independente do modo de depuração. O importante é manter consistência entre servidor, IDE e navegador.

Integração com um frontend React em HTTPS

Em aplicações com frontend separado, rodar o React também em HTTPS alinha cookies, CORS e políticas do navegador. O servidor de desenvolvimento do React aceita variáveis de ambiente para ativar o canal seguro e apontar certificado e chave. Scripts personalizados no package.json facilitam o início consistente do projeto. O exemplo a seguir assume os mesmos certificados do backend local.

{
  "name": "meu-frontend",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "start-https": "HTTPS=true SSL_CRT_FILE=%USERPROFILE%/certs/cert.pem SSL_KEY_FILE=%USERPROFILE%/certs/key.pem react-scripts start",
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
}

Em sistemas Unix, variáveis podem usar caminhos com home (~) ou absolutos, respeitando o shell vigente. Em Windows, o caminho de usuário com %USERPROFILE% facilita a portabilidade do script. A execução do script ocorre pelo gerenciador de pacotes com o nome do script. O comando padrão chama o script personalizado.

# iniciar o React em HTTPS usando os certificados locais
npm run start-https

Ao combinar backend e frontend em HTTPS, requisições a APIs e cookies same-site funcionam como em produção. Caso portas diferentes sejam usadas, configurar CORS e cabeçalhos apropriados no backend evita bloqueios. Ambientes com proxy de desenvolvimento podem unificar portas e domínios, mas não é obrigatório. O objetivo é garantir contexto seguro nos dois lados.

Problemas comuns e soluções práticas

Quando o navegador indica “certificado inválido”, a causa mais frequente é um SAN ausente para o host acessado. Regenerar o certificado com subjectAltName adequado resolve o alerta imediatamente. Outro erro envolve caminhos incorretos ao passar --cert-file e --key-file, corrigido ao usar caminhos absolutos. Em shells que não expandem ~, substituir pelo caminho completo elimina falhas silenciosas.

Erros como “PEM routines” sugerem arquivos truncados ou permissão incorreta na chave privada. Recriar o par de chaves e ajustar as permissões do arquivo corrigem o problema. Loops de redirecionamento entre HTTP e HTTPS surgem quando SECURE_SSL_REDIRECT conflita com um proxy sem o cabeçalho X-Forwarded-Proto. Nesses casos, definir SECURE_PROXY_SSL_HEADER alinha a detecção do esquema.

Alertas de “conteúdo misto” aparecem quando scripts ou imagens são servidos por HTTP dentro de uma página HTTPS. Corrigir URLs absolutas e bases de API remove o alerta e restabelece o cadeado de segurança. Em testes com bibliotecas HTTP do lado do servidor, validar o parâmetro verify quando usando certificados não confiáveis evita ruído nos logs. A preferência, porém, é confiar o certificado no sistema e manter verify ativo.

Ao integrar frontend e backend, tokens CSRF bloqueados indicam origem não confiável ou esquema incorreto em CSRF_TRUSTED_ORIGINS. Ajustar o esquema https e a porta correta elimina o 403 inesperado. Cookies sem o sinalizador Secure não são enviados em HTTPS, o que impede sessões persistentes; ativar SESSION_COOKIE_SECURE e CSRF_COOKIE_SECURE evita esse efeito. Essas correções aproximam o comportamento do ambiente real.

Boas práticas e organização dos arquivos

Certificados e chaves privadas não devem ser versionados no repositório do código. Um .gitignore específico impede o vazamento desses ativos sensíveis. A estrutura de pastas em ~/certs facilita a repetição e a padronização entre máquinas. Renovar certificados periodicamente reduz surpresas por expiração durante uma demonstração.

Ambientes que compartilham máquinas exigem permissões restritas nos arquivos de chave privada. Caminhos consistentes nos scripts evitam diferenças entre sistemas e terminais. Variáveis de ambiente centralizam ajustes, principalmente em projetos com múltiplos serviços. Registrar comandos de inicialização em README interno reforça a prática compartilhada do time.

Como era e como será: comparativo prático

No cenário anterior, o servidor rodava com HTTP simples e sem restrições de cookies, mascarando problemas de segurança. As integrações que exigiam HTTPS, como login social e APIs com políticas estritas, não podiam ser testadas integralmente. Após a mudança, o tráfego passa a ser cifrado, os cookies são marcados como Secure e as políticas de navegador são aplicadas. Esse novo estado permite depuração antecipada de falhas que só apareceriam em produção.

Antes, bastava um runserver básico e as páginas carregavam sem cadeado, ainda que funcionassem parcialmente. Depois, o runserver_plus ou um servidor ASGI com TLS replica o ambiente final, inclusive em erros típicos de certificado. O time testa fluxo completo de autenticação, proteção CSRF e recursos que exigem contexto seguro. O resultado é uma migração para produção mais previsível e com menos retrabalho.

Exemplos completos: projeto Django ajustado para HTTPS local

Um trecho de settings.py com todas as diretivas relevantes ilustra o conjunto recomendado para desenvolvimento seguro. O bloco a seguir reúne cookies, CSRF, redirecionamento, hosts e origens, com comentários breves. Essas linhas já bastam para um teste confiável com runserver_plus, Uvicorn ou Daphne. Ajustes pontuais de porta e domínio atendem variações do projeto.

# settings.py (exemplo coeso para HTTPS local)

DEBUG = True
SECRET_KEY = "chave-secreta-local-apenas-para-dev"

ALLOWED_HOSTS = ['localhost', '127.0.0.1', '[::1]']

# Cookies em canal seguro
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

# CSRF confiando no host HTTPS local (ajustar porta se diferente)
CSRF_TRUSTED_ORIGINS = ['https://localhost:8000']

# Redirecionar HTTP->HTTPS
SECURE_SSL_REDIRECT = True

# HSTS desabilitado em dev
SECURE_HSTS_SECONDS = 0
SECURE_HSTS_INCLUDE_SUBDOMAINS = False
SECURE_HSTS_PRELOAD = False

# Caso haja proxy TLS na frente do Django, descomentar:
# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

INSTALLED_APPS = [
    # ... apps do projeto ...
    'django.contrib.staticfiles',
    'django_extensions',  # habilita runserver_plus
]

# Static e Media em dev continuam funcionais
STATIC_URL = '/static/'
MEDIA_URL = '/media/'

Com o settings ajustado, o comando de execução usa o certificado confiável do sistema. O processo resulta em um servidor local servindo HTTPS de ponta a ponta. O cadeado no navegador indica o sucesso da configuração e habilita APIs dependentes de contexto seguro. Logs de requisição mostram o esquema correto e confirmam a proteção aplicada.

# execução típica com runserver_plus e certificados persistentes
python manage.py runserver_plus --cert-file ~/certs/cert.pem --key-file ~/certs/key.pem localhost:8000

Conclusão

Ativar HTTPS no localhost com Django traz o ambiente de desenvolvimento para o mesmo patamar de segurança e comportamento do ambiente de produção. A criação correta do certificado com SAN, a confiança do sistema operacional e os ajustes do settings.py formam a base sólida. O uso de runserver_plus ou de servidores ASGI com TLS completa o ciclo com comandos simples e reprodutíveis. A integração opcional com React e as práticas de organização asseguram fluxo estável, enquanto as soluções para problemas comuns evitam interrupções no trabalho diário.