Automatizando a geração de certificados SSL locais para ambientes de desenvolvimento

Sabe aquele projeto que você está iniciando o desenvolvimento e já deixou tudo configurado pra ser acessado apenas via HTTPS no intuito de refletir como será em produção? Aí você configura um virtualhost para acessá-lo, mas ao entrar:

Essa é a imagem que melhor define o sentimento de “a pain in the ass“. A primeira coisa que a gente pensa é: e se eu gerar um certificado self-signed? Bem, pode resolver o problema no sentido do navegador te permitir acessar o domínio (com você colocando uma exceção pra ele), mas ainda assim, ele continua dizendo que a conexão não é segura:

E isso é uma coisa que incomoda pra caramba (pelo menos a mim :P). O problema é que os navegadores não conseguem reconhecer a autoridade de certificação de um certificado self-signed gerado da forma tradicional.

E, para criar uma CA (certificate authority) e adicioná-la na root store do sistema (onde os certificados são gerenciados. No caso do macOS isso é feito no software Keychain), não é algo tão trivial de se fazer, como você pode visualizar nesse tutorial aqui:

https://gist.github.com/KennedyTedesco/143576402fd7d9b49fbdedc9e417e5f9

Mas, e se eu te contar que tem uma ferramenta que abstrai toda essa dificuldade? Pois é! É o que veremos a seguir.

Antes, entretanto, é bom pontuar que esse artigo foi escrito para quem já tem o servidor web configurado com uma virtualhost, com o domínio em questão em /etc/hosts apontando para o host 127.0.0.1 e que agora precisa fazer um certificado local ser devidamente validado nos navegadores. O artigo não entrará em detalhes de configuração de servidor, configuração de aplicações etc.

Docker - Fundamentos
Curso de Docker - Fundamentos
CONHEÇA O CURSO

Gerando certificados SSL locais assinados com a mkcert

A mkcert é uma daquelas ferramentas indispensáveis para se montar um ambiente de desenvolvimento que dê gosto de trabalhar. Ela abstrai toda a dificuldade e complexidade de gerar certificados, como também de gerar uma CA (certificate authority) local. A única coisa que a mkcert não faz é instalar o certificado no seu servidor local, mas isso nem é algo tão complicado de se fazer.

Primeiro de tudo temos que instalar a ferramenta. Se você usa macOS, o Homebrew pode ser utilizado:

$ brew install mkcert

Se você usa Windows, você pode usar o gerenciador de pacotes Chocolatey:

$ choco install mkcert

Se você usa Linux, na documentação da mkcert mostra como pode ser feito.

Instalando a CA:

Para instalar a CA na root store, basta executar uma única vez:

$ mkcert -install

Criando o certificado:

$ mkcert teste.test "*.teste.test" www.teste.test

Nesse exemplo a ferramenta criará um certificado que será válido para o domínio teste.test e para todos os sub-domínios de primeiro nível dele.

O resultado da execução será:

~> mkcert teste.test "*.teste.test" www.teste.test
Using the local CA at "/Users/kennedytedesco/Library/Application Support/mkcert" ✨

Created a new certificate valid for the following names 📜
 - "teste.test"
 - "*.teste.test"
 - "www.teste.test"

Reminder: X.509 wildcards only go one level deep, so this won't match a.b.teste.test ℹ️

The certificate is at "./teste.test+2.pem" and the key at "./teste.test+2-key.pem" ✅

Tanto o certificado quanto a chave privada foram salvos no diretório do meu usuário. Tendo o certificado teste.test+2.pem e a chave privada dele teste.test+2-key.pem, já conseguimos configurar, por exemplo, o nginx para servi-los.

Configurando os certificados no Nginx

Agora, é preciso que você copie o certificado e a chave privada para o local onde o seu nginx consiga ter acesso para carregá-los. Você pode até renomeá-los se quiser.

No final do bloco server do virtualhost do seu projeto, basta adicionar o caminho para eles:

ssl_certificate /etc/nginx/ssl/teste.test.pem;
ssl_certificate_key /etc/nginx/ssl/teste.test.key.pem;  

Por exemplo:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    index index.php;
    root /var/www/teste;

    server_name teste.test www.teste.test;
    access_log off;

    location / {
         try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    ssl_certificate /etc/nginx/ssl/teste.test.pem;
    ssl_certificate_key /etc/nginx/ssl/teste.test.key.pem;  
}

No Apache seria algo como:

SSLEngine on
SSLCertificateFile "/private/etc/apache2/ssl/teste.test.pem"
SSLCertificateKeyFile "/private/etc/apache2/ssl/teste.test.key.pem"

Exemplo em funcionamento no Firefox:

Use e abuse da mkcert. Happy coding!

Ah, se você precisa gerar certificados SSL para o seu servidor em produção, veja esse artigo: Gerando certificados SSL gratuitos com Certbot.

Deixe seu comentário

Head de desenvolvimento. Vasta experiência em desenvolvimento Web com foco em PHP. Graduado em Sistemas de Informação. Pós-graduando em Arquitetura de Software Distribuído pela PUC Minas. Zend Certified Engineer (ZCE) e Coffee Addicted Person (CAP). @KennedyTedesco