Existem várias maneiras de melhorar a flexibilidade e segurança do seu aplicativo Node.js. O uso de um proxy reverso como o Nginx oferece a você a capacidade de carregar solicitações de balanceamento de carga, conteúdo de cache estático e de* implementar a Segurança em Camada*s de Transporte (TLS). Ao habilitar o HTTPS criptografado no seu servidor, garante-se que a comunicação para o seu aplicativo e vinda dele permaneça segura.
A implementação de um proxy reverso com TLS/SSL em contêineres envolve um conjunto diferente de procedimentos do trabalho em um sistema operacional de host. Por exemplo, se estivesse obtendo certificados do Let’s Encrypt para um aplicativo em execução em um servidor, deveria instalar o software necessário diretamente no seu host. Os contêineres permitem que você utilize uma abordagem diferente. Ao usar o Docker Compose, é possível criar contêineres para o seu aplicativo, seu servidor Web e o cliente Certbot que permite você de obter seus certificados. Ao seguir estes passos, você pode aproveitar a modularidade e a portabilidade de um fluxo de trabalho em contêiner.
Neste tutorial, será implantado um aplicativo Node.js com um proxy reverso Nginx usando o Docker Compose. Você receberá certificados TLS/SSL para o domínio associados ao seu aplicativo e garantirá que ele receba uma classificação de segurança elevada do SSL Labs. Por fim, será configurado um trabalho cron
para renovar seus certificados para que seu domínio permaneça seguro.
Para seguir este tutorial, será necessário:
Um servidor Ubuntu 18.04, um usuário não raiz com privilégios sudo
e um firewall ativo. Para saber como configurar isso, consulte este guia de configuração inicial do servidor.
O Docker e o Docker Compose instalados no seu servidor. Como orientação na instalação do Docker, siga os Passos 1 e 2 de Como instalar e usar o Docker no Ubuntu 18.04. Como orientação na instalação do Compose, siga o Passo 1 de Como instalar o Docker Compose no Ubuntu 18.04.
Um nome de domínio registrado. Este tutorial usará o example.com do início ao fim. Você pode obter um domínio gratuitamente através do Freenom, ou usar o registrador de domínios de sua escolha.
Ambos os registros de DNS a seguir serão configurados para o seu servidor. Você pode seguir esta introdução para o DNS da DigitalOcean para obter mais detalhes sobre como adicioná-los a uma conta da DigitalOcean, caso seja o que estiver usando:
example.com
apontando para o endereço de IP público do seu servidor.example.com
apontando para o endereço IP público do seu servidor.Como primeiro passo, clonaremos o repositório com o código do aplicativo Node, que inclui o Dockerfile que usaremos na construção da nossa imagem de aplicativo com o Compose. Podemos testar primeiro o aplicativo a partir de sua construção e execução com o comando docker run,
sem um proxy reverso ou SSL.
No diretório home do seu usuário não raiz, clone o repositório nodejs-image-demo
da conta GitHub da Comunidade DigitalOcean. Este repositório inclui o código da configuração descrito em Como construir um aplicativo Node.js com o Docker.
Clone o repositório em um diretório chamado node_project
:
- git clone https://github.com/do-community/nodejs-image-demo.git node_project
Vá para o diretório node_project
:
- cd node_project
Neste diretório, há um Dockerfile que contém instruções para a construção de um aplicativo Node usando a imagem do Docker node:10
e o conteúdo do seu diretório de projeto atual. Você pode olhar o conteúdo do Dockerfile digitando:
- cat Dockerfile
OutputFROM node:10-alpine
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY package*.json ./
USER node
RUN npm install
COPY --chown=node:node . .
EXPOSE 8080
CMD [ "node", "app.js" ]
Essas instruções constroem uma imagem do Node através da cópia do código do projeto do diretório atual para o contêiner e instalação de dependências com o npm install
. Elas também se aproveitam do salvamento em cache e disposição em camadas da imagem. Isso é feito pela separação da cópia do package.json
e package-lock.json
, que contém as dependências listadas do projeto, da cópia do resto do código do aplicativo. Por fim, as instruções especificam que o contêiner será executado como o usuário node não raiz com as permissões apropriadas definidas no código do aplicativo e no diretório node_modules
.
Para obter mais informações sobre este Dockerfile e práticas recomendadas da imagem do Node, consulte a discussão completa no Passo 3 de Como construir um aplicativo Node.js com o Docker.
Para testar o aplicativo sem o SSL, construa e identifique a imagem usando o docker build
e o sinalizador -t
. Vamos nomear a imagem node-demo
, mas você pode dar a ela o nome que quiser:
- docker build -t node-demo .
Assim que o processo de construção for concluído, você pode listar suas imagens com o docker images
:
- docker images
Você verá o seguinte resultado, confirmando a compilação da imagem do aplicativo:
OutputREPOSITORY TAG IMAGE ID CREATED SIZE
node-demo latest 23961524051d 7 seconds ago 73MB
node 10-alpine 8a752d5af4ce 3 weeks ago 70.7MB
Em seguida, crie o contêiner com o docker run
. Vamos incluir três sinalizadores com este comando:
-p
: publica a porta no contêiner e a mapeia para uma porta no nosso host. Usaremos a porta 80
no host, mas sinta-se a vontade para escolher outra se necessário, caso tenha outro processo em execução naquela porta. Para obter mais informações sobre como isso funciona, veja esta discussão nos documentos do Docker sobre associação de portas.-d
: executa o contêiner em segundo plano.--name
: permite-nos dar ao contêiner um nome memorável.Execute o comando a seguir para criar o contêiner:
- docker run --name node-demo -p 80:8080 -d node-demo
Verifique seus contêineres em execução com o docker ps
:
- docker ps
Você verá o resultado que confirma que o seu contêiner do aplicativo está funcionando:
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo
Agora, você pode visitar seu domínio para testar sua configuração: http://example.com
. Lembre-se de substituir o example.com
pelo seu próprio nome de domínio. Seu aplicativo exibirá a seguinte página de destino:
Agora que você testou o aplicativo, pare o contêiner e remova as imagens. Use o docker ps
novamente para obter seu CONTAINER ID
:
- docker ps
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo
Pare o contêiner com o docker stop
. Certifique-se de substituir o CONTAINER ID
listado aqui pelo CONTAINER ID
do seu aplicativo:
- docker stop 4133b72391da
Agora, é possível remover o contêiner parado e todas as imagens, incluindo imagens não utilizadas e penduradas, com o docker system prune
e o sinalizador -a
:
- docker system prune -a
Digite y
quando solicitado na saída para confirmar que você gostaria de remover o contêiner e imagens parados. Fique ciente de que isso também removerá seu cache de construção.
Com sua imagem de aplicativo testada, siga em frente para a construção do resto da sua configuração com o Docker Compose.
Com nosso aplicativo Dockerfile funcionando, podemos criar um arquivo de configuração para executar nosso contêiner Nginx. Começaremos com uma configuração mínima que incluirá nosso nome de domínio, root do documento, informações de proxy e um bloco de localização para dirigir os pedidos do Certbot ao diretório .well-known
. Lá, ele colocará um arquivo temporário para validar que o DNS para nosso domínio resolva para nosso servidor.
Primeiramente, crie um diretório no diretório atual do projeto para o arquivo de configuração:
- mkdir nginx-conf
Abra o arquivo com o nano
ou com o seu editor favorito:
- nano nginx-conf/nginx.conf
Adicione o seguinte bloco de servidor para servir como proxy para os pedidos de usuário para o contêiner do seu aplicativo Node e redirecionar os pedidos do Certbot ao diretório .well-known
. Certifique-se de substituir o example.com
pelo seu próprio nome de domínio:
server {
listen 80;
listen [::]:80;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name example.com www.example.com;
location / {
proxy_pass http://nodejs:8080;
}
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
}
Este bloco de servidor nos permitirá iniciar o contêiner Nginx como um proxy reverso, que passará pedidos para nosso contêiner do aplicativo Node. Ele também nos permitirá usar o plug-in webroot do Certbot para obter certificados para nosso domínio. Este plug-in depende do método de validação HTTP-01, que usa um pedido HTTP para provar que o Certbot pode acessar recursos de um servidor que responde a um dado nome de domínio.
Assim que terminar a edição, salve e feche o arquivo. Para aprender mais sobre o servidor Nginx e os algoritmos de blocos de localização, consulte este artigo Entendendo o servidor Nginx e os algoritmos de seleção de blocos de localização.
Com os detalhes de configuração do servidor Web funcionando, podemos seguir em frente para a criação do nosso arquivo docker-compose.yml
, que nos permitirá criar nossos serviços de aplicativo e o contêiner do Certbot que usaremos para obter nossos certificados.
O arquivo docker-compose.yml
definirá nossos serviços, incluindo o aplicativo Node e o servidor Web. Ele especificará detalhes como volumes nomeados, que serão críticos para compartilhar credenciais SSL entre contêineres, além de informações de rede e portas. Ele também nos permitirá especificar comandos específicos para serem executados quando nossos contêineres forem criados. Este arquivo é o recurso central que definirá como nossos serviços funcionarão em conjunto.
Abra o arquivo no seu diretório atual:
- nano docker-compose.yml
Primeiro, defina o serviço de aplicativo:
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
A definição de serviço nodejs
inclui o seguinte:
build
: define as opções de configuração, incluindo o context
e dockerfile
, que serão aplicadas quando o Compose construir a imagem do aplicativo. Se quisesse usar uma imagem existente de um registro como o Docker Hub, poderia usar como alternativa a instrução image
, com informações sobre seu nome de usuário, repositório e tag da imagem.context
: define o contexto de compilação para a compilação de imagem do aplicativo. Neste caso, é o diretório atual do projeto.dockerfile
: especifica o Dockerfile que o Compose usará para a compilação — o Dockerfile que você olhou no Passo 1.image
, container_name
: aplicam nomes à imagem e contêiner.restart
: define a política de reinício. A padrão é no
, mas definimos o contêiner para reiniciar a menos que ele seja interrompido.Note que não estamos incluindo bind mounts com este serviço, uma vez que nossa configuração está focada na implantação e não no desenvolvimento. Para obter mais informações, consulte a documentação do Docker sobre bind mounts e volumes.
Para habilitar a comunicação entre os contêineres do aplicativo e do servidor Web, adicionaremos também uma rede bridge chamada app-network
abaixo da definição de reinicialização:
services:
nodejs:
...
networks:
- app-network
Uma rede bridge definida pelo usuário permite a comunicação entre contêineres no mesmo host daemon do Docker. Isso simplifica o tráfego e a comunicação dentro do seu aplicativo, uma vez que todas as portas entre os contêineres na mesma rede bridge são abertas, ao mesmo tempo em que nenhuma porta é exposta ao mundo exterior. Assim, é possível ser seletivo abrindo apenas as portas que você precisar para expor seus serviços front-end.
Em seguida, defina o serviço webserver
:
...
webserver:
image: nginx:mainline-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- nodejs
networks:
- app-network
Algumas das configurações que definimos para o serviço nodejs
permanecem as mesmas, mas também fizemos as seguintes alterações:
image
: diz ao Compose para puxar a última imagem Nginx baseada em Alpine do Docker Hub. Para obter mais informações sobre imagens alpine,
consulte o Passo 3 de Como construir um aplicativo Node.js com o Docker.ports
: expõe a porta 80
para habilitar as opções de configuração que definimos em nossa configuração do Nginx.Também especificamos os seguintes volumes nomeados e bind mounts:
web-root:/var/www/html
: adicionará os ativos estáticos do nosso site, copiados para um volume chamado web-root
, para o diretório /var/www/html
no contêiner../nginx-conf:/etc/nginx/conf.d
: irá associar a montagem do diretório de configuração Nginx no host ao diretório relevante no contêiner, garantindo que quaisquer alterações que façamos em arquivos no host serão refletidas no contêiner.certbot-etc:/etc/letsencrypt
: irá montar os certificados e chaves relevantes do Let’s Encrypt do nosso domínio para o diretório apropriado no contêiner.certbot-var:/var/lib/letsencrypt
: monta o diretório de trabalho padrão do Let’s Encrypt para o diretório apropriado no contêiner.Em seguida, adicione as opções de configuração para o contêiner certbot
. Certifique-se de substituir as informações de domínio e e-mail pelo seu próprio nome de domínio e e-mail:
...
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com
Esta definição diz ao Compose para puxar a imagem certbot/certbot do Docker Hub. Ela também usa volumes nomeados para compartilhar recursos com o contêiner do Nginx, incluindo os certificados de domínio e chaves no certbot-etc
, o diretório de trabalho do Let’s Encrypt no certbot-var
e o código do aplicativo no web-root
.
Novamente, usamos o depends_on
para especificar que o contêiner do certbot
deve ser iniciado assim que o serviço webserver
estiver funcionando.
Também incluímos uma opção command
que especifica o comando a ser executado quando o contêiner for iniciado. Ele inclui o subcomando certonly
com as seguintes opções:
--webroot
: diz ao Certbot para usar o plug-in webroot para colocar arquivos na pasta webroot para autenticação.--webroot-path
: especifica o caminho do diretório webroot.--email
: seu e-mail escolhido para o registro e recuperação.--agree-tos
: especifica que você concorda com os termos do Acordo do Assinante do protocolo ACME.--no-eff-email
: diz ao Certbot que você não deseja compartilhar seu e-mail com a Electronic Frontier Foundation (EFF). Sinta-se à vontade para omitir isso se preferir.--staging
: diz ao Certbot que você deseja usar o ambiente de preparo do Let’s Encrypt para obter certificados de teste. Usar essa opção permite que você teste suas opções de configuração e evite possíveis limites de solicitação de domínio. Para obter mais informações sobre esses limites, consulte a documentação sobre limites de taxa do Let’s Encrypt.-d
: permite que você especifique os nomes de domínio que gostaria de aplicar ao seu pedido. Neste caso, incluímos o example.com
e www.example.com
. Certifique-se de substituí-los pelas suas próprias preferências de domínio.Como passo final, adicione as definições de volume e rede. Certifique-se de substituir o nome de usuário presente aqui pelo seu usuário não raiz:
...
volumes:
certbot-etc:
certbot-var:
web-root:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/views/
o: bind
networks:
app-network:
driver: bridge
Nossos volumes nomeados incluem nosso certificado Certbot e os volumes de diretórios de trabalho, além dos volume para os ativos estáticos do nosso site, o web-root
. Na maioria dos casos, o driver padrão para os volumes do Docker é o driver local
, que no Linux aceita opções semelhantes ao comando mount
. Graças a isso, é possível especificar uma lista de opções de drivers com o driver_opts
que montam o diretório views
no host, sendo que estes contém os ativos estáticos do nosso aplicativo, além do volume em tempo de execução. O conteúdo do diretório pode ser, então, compartilhado entre contêineres. Para obter mais informações sobre o conteúdo do diretório views
, consulte o Passo 2 de Como construir um aplicativo Node.js com o Docker.
O arquivo docker-compose.yml
se parecerá com isto quando terminar:
version: '3'
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
networks:
- app-network
webserver:
image: nginx:mainline-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
depends_on:
- nodejs
networks:
- app-network
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com
volumes:
certbot-etc:
certbot-var:
web-root:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/views/
o: bind
networks:
app-network:
driver: bridge
Com as definições de serviço instaladas, você está pronto para iniciar os contêineres e testar seus pedidos de certificado.
Podemos iniciar nossos contêineres com o docker-compose up
, que criará e executará nossos contêineres e serviços na ordem que especificamos. Se nossos pedidos de domínio forem bem sucedidos, veremos o status correto de saída no nosso resultado e os certificados corretos montados na pasta /etc/letsencrypt/live
no contêiner webserver
.
Crie os serviços com o docker-compose up
e o sinalizador -d
, os quais executarão os contêineres nodejs
e webserver
em segundo plano:
- docker-compose up -d
Você verá um resultado confirmando que seus serviços foram criados:
OutputCreating nodejs ... done
Creating webserver ... done
Creating certbot ... done
Com o uso do docker-compose ps
, verifique o status dos seus serviços:
- docker-compose ps
Se tudo ocorreu bem, seus serviços nodejs
e webserver
devem estar Up
e o contêiner certbot
terá finalizado com uma mensagem de status 0
:
Output Name Command State Ports
------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
nodejs node app.js Up 8080/tcp
webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
Se você ver qualquer outra coisa além de Up
na coluna State
para os serviços nodejs
e webserver
, ou um status de saída que não seja 0
para o contêiner certbot
, certifique-se de verificar os registros de serviço com o comando docker-compose logs
:
- docker-compose logs service_name
Agora, é possível verificar se suas credenciais foram instaladas no contêiner webserver
com o docker-compose exec
:
- docker-compose exec webserver ls -la /etc/letsencrypt/live
Se seu pedido foi bem sucedido, você verá um resultado similar a este:
Outputtotal 16
drwx------ 3 root root 4096 Dec 23 16:48 .
drwxr-xr-x 9 root root 4096 Dec 23 16:48 ..
-rw-r--r-- 1 root root 740 Dec 23 16:48 README
drwxr-xr-x 2 root root 4096 Dec 23 16:48 example.com
Agora que você sabe que seu pedido será bem sucedido, edite a definição do serviço certbot
para remover o sinalizador --staging
.
Abra o docker-compose.yml
:
- nano docker-compose.yml
Encontre a seção do arquivo com a definição de serviço do certbot
e substitua o sinalizador --staging
na opção command
pelo sinalizador --force-renewal
, o qual dirá ao Certbot que você quer solicitar um novo certificado com os mesmos domínios de um certificado existente. A definição de serviço do certbot
deve agora se parecer com isto:
...
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- web-root:/var/www/html
depends_on:
- webserver
command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
...
Agora, é possível executar o docker-compose up
para recriar o contêiner do certbot
e seus volumes relevantes. Também vamos incluir a opção --no-deps
para dizer ao Compose que ele pode pular a inicialização do serviço webserver
, já que ele já está em funcionamento:
- docker-compose up --force-recreate --no-deps certbot
Você verá o resultado indicando que o seu pedido de certificado foi bem-sucedido:
Outputcertbot | IMPORTANT NOTES:
certbot | - Congratulations! Your certificate and chain have been saved at:
certbot | /etc/letsencrypt/live/example.com/fullchain.pem
certbot | Your key file has been saved at:
certbot | /etc/letsencrypt/live/example.com/privkey.pem
certbot | Your cert will expire on 2019-03-26. To obtain a new or tweaked
certbot | version of this certificate in the future, simply run certbot
certbot | again. To non-interactively renew *all* of your certificates, run
certbot | "certbot renew"
certbot | - Your account credentials have been saved in your Certbot
certbot | configuration directory at /etc/letsencrypt. You should make a
certbot | secure backup of this folder now. This configuration directory will
certbot | also contain certificates and private keys obtained by Certbot so
certbot | making regular backups of this folder is ideal.
certbot | - If you like Certbot, please consider supporting our work by:
certbot |
certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
certbot | Donating to EFF: https://eff.org/donate-le
certbot |
certbot exited with code 0
Com seus certificados instalados, você pode seguir em frente para modificar sua configuração do Nginx para incluir o SSL.
Habilitar o SSL na nossa configuração Nginx envolverá a adição de um redirecionamento do HTTP para o HTTPS e a especificação dos nossos certificados e locais de chave SSL. Isso também envolverá especificar nosso grupo Diffie-Hellman, que usaremos para o Perfect Forward Secrecy.
Como será recriado o serviço webserver
para incluir essas adições, você pode interrompê-lo agora:
- docker-compose stop webserver
Em seguida, crie um diretório no seu diretório atual de projeto para sua chave Diffie-Hellman:
- mkdir dhparam
Gere sua chave com o comando openssl
:
- sudo openssl dhparam -out /home/sammy/node_project/dhparam/dhparam-2048.pem 2048
A chave será gerada após alguns instantes.
Para adicionar as informações relevantes do Diffie-Hellman e SSL na sua configuração do Nginx, remova primeiro o arquivo de configuração do Nginx que você criou mais cedo:
- rm nginx-conf/nginx.conf
Abra outra versão do arquivo:
- nano nginx-conf/nginx.conf
Adicione o seguinte código ao arquivo para redirecionar o HTTP para o HTTPS e adicione credenciais, protocolos e cabeçalhos de segurança do protocolo SSL. Lembre-se de substituir o example.com
pelo seu próprio domínio:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_buffer_size 8k;
ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
ssl_ecdh_curve secp384r1;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
location / {
try_files $uri @nodejs;
}
location @nodejs {
proxy_pass http://nodejs:8080;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# enable strict transport security only if you understand the implications
}
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
}
O bloco de servidor HTTP especifica o webroot dos pedidos de renovação do Certbot para o diretório .well-known/acme-challenge
. Isso também inclui uma diretriz de reescrita, que direciona os pedidos do HTTP para o diretório raiz para o HTTPS.
O bloco de servidor HTTPS habilita o ssl
e o http2
. Para ler mais sobre como o HTTP/2 itera nos protocolos HTTP e os benefícios que ele pode ter para o desempenho do site, consulte a introdução de Como configurar o Nginx com suporte HTTP/2 no Ubuntu 18.04. Este bloco também inclui uma série de opções para garantir que você esteja usando os protocolos e criptografias SSL mais atualizados e que o grampeamento OSCP esteja ligado. O grampeamento OSCP permite a oferta de uma resposta com a data marcada da sua autoridade de certificação durante o handshake TLS, o que pode acelerar o processo de autenticação.
O bloco também especifica suas credenciais e locais de chave do SSL e Diffie-Hellman.
Por fim, transferimos as informações de passagem de proxy para este bloco, incluindo um bloco de localização com uma diretriz try_files
, direcionando pedidos para nosso contêiner do aplicativo Node.js de alias, e um bloco de localização para aquele alias, que inclui cabeçalhos de segurança que nos permitirão obter classificações A em coisas como os sites de teste de servidor SSL Labs e Security Headers. Estes cabeçalhos incluem o X-Frame-Options
, X-Content-Type-Options
, Referrer Policy
, Content-Security-Policy
, e X-XSS-Protection
. O cabeçalho HTTP Strict Transport Security
(HSTS) é retirado do comentário - habilite isso apenas se você entender as implicações e avaliou sua funcionalidade de “precarregamento”.
Assim que terminar a edição, salve e feche o arquivo.
Antes de recriar o serviço webserver
, será necessário adicionar algumas coisas na definição de serviço no seu arquivo docker-compose.yml
, incluindo informações relevantes de porta para o HTTPS e uma definição de volume do Diffie-Hellman.
Abra o arquivo:
- nano docker-compose.yml
Na definição do serviço webserver
, adicione o seguinte mapeamento de portas e o volume nomeado dhparam
:
...
webserver:
image: nginx:latest
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- web-root:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- dhparam:/etc/ssl/certs
depends_on:
- nodejs
networks:
- app-network
Em seguida, adicione o volume dhparam
às suas definições de volumes
:
...
volumes:
...
dhparam:
driver: local
driver_opts:
type: none
device: /home/sammy/node_project/dhparam/
o: bind
De maneira similar ao volume web-root
, o volume dhparam
montará a chave Diffie-Hellman armazenada no host para o contêiner webserver
.
Salve e feche o arquivo quando você terminar a edição.
Recrie o serviço webserver
:
- docker-compose up -d --force-recreate --no-deps webserver
Verifique seus serviços com o docker-compose ps
:
- docker-compose ps
Você deve ver um resultado indicando que seus serviços nodejs
e webserver
estão funcionando:
Output Name Command State Ports
----------------------------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
nodejs node app.js Up 8080/tcp
webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
Por fim, visite seu domínio para garantir que tudo está funcionando conforme esperado. Navegue com seu browser até https://example.com
, certificando-se de substituir o example.com
pelo seu próprio nome de domínio. Você verá a seguinte página de destino:
Você também deve ver o ícone de cadeado no indicador de segurança do seu navegador. Se quiser, navegue até a página de destino do teste de servidor do SSL Labs, ou a página de destino do teste de servidor do Security Headers. As opções de configuração que incluímos devem garantir ao seu site uma classificação A em ambos.
Os certificados do Let’s Encrypt são válidos por 90 dias, então você vai querer configurar um processo de renovação automatizado para garantir que eles não expirem. Uma maneira de fazer isso é criando um trabalho com o utilitário de agendamento cron
. Neste caso, vamos agendar uma tarefa do cron
usando um script que renovará nossos certificados e recarregará nossa configuração do Nginx.
Abra um script chamado ssl_renew.sh
no seu diretório de projeto:
- nano ssl_renew.sh
Adicione o seguinte código ao script para renovar seus certificados e recarregar a configuração do seu servidor Web:
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/sammy/node_project/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Primeiro, este script atribui o binário docker-compose
a uma variável chamada COMPOSE
e especifica a opção --no-ansi
, a qual executará os comandos do docker-compose
sem os caracteres de controle do ANSI. Em seguida, ele faz o mesmo com o binário docker
. Por fim, ele muda para o diretório do projeto ~/wordpress
e executa os seguintes comandos docker-compose:
docker-compose run
: iniciará um contêiner certbot
e substituirá o comando
fornecido em nossa definição de serviço certbot
. Em vez de usar o subcomando certonly
vamos usar o subcomando renew
aqui, o qual renovará os certificados que estão próximos de expirar. Incluímos a opção --dry-run
aqui para testar nosso script.docker-compose kill
: enviará um sinal SIGHUP
para o contêiner webserver
recarregar a configuração do Nginx. Para obter mais informações sobre o uso deste processo para recarregar sua configuração do Nginx, consulte este post do blog do Docker sobre a implantação da imagem oficial do Nginx com o Docker.Na sequência, ele executa o docker system prune
para remover todos os contêineres e imagens não utilizados.
Feche o arquivo quando terminar a edição. Torne-o executável:
- chmod +x ssl_renew.sh
Em seguida, abra seu arquivo root crontab
para executar o script de renovação em um intervalo especificado:
- sudo crontab -e
Se esta for a primeira vez que você edita esse arquivo, será solicitado que escolha um editor:
no crontab for root - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.basic
4. /usr/bin/vim.tiny
Choose 1-4 [2]:
...
No final do arquivo, adicione a seguinte linha:
...
*/5 * * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
Isso definirá intervalos de trabalho de cinco minutos cada, para que você possa testar se o seu pedido de renovação funcionou como o previsto. Também criamos um arquivo de registro, cron.log
, para gravar o resultado relevante do trabalho.
Após cinco minutos, verifique o cron.log
para ver se o pedido de renovação foi bem-sucedido:
- tail -f /var/log/cron.log
Um resultado confirmando uma renovação bem-sucedida deve aparecer:
Output- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates below have not been saved.)
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Killing webserver ... done
Agora, é possível modificar o arquivo crontab
para definir um intervalo diário. Para executar o script todos os dias ao meio-dia, por exemplo, você modificaria a última linha do arquivo para que fique com a seguinte aparência:
...
0 12 * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
Você também vai querer remover a opção --dry-run
do seu script ssl_renew.sh
:
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/sammy/node_project/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Seu trabalho cron
irá garantir que seus certificados do Let’s Encrypt não expirem, renovando-os quando forem elegíveis para tanto. Você também pode configurar um rodízio de registros com o utilitário Logrotate para rodiziar e comprimir seus arquivos de registro.
Você usou contêineres para configurar e executar um aplicativo Node com um proxy reverso Nginx. Você também utilizou certificados SSL para proteger o domínio do seu aplicativo e configurou um trabalho cron
para renovar esses certificados quando necessário.
Se estiver interessado em aprender mais sobre plug-ins do Let’s Encrypt, consulte nossos artigos sobre o uso do plug-in Nginx ou do plug-in standalone.
Você também pode aprender mais sobre o Docker Compose consultando os seguintes recursos:
A documentação do Compose também é um ótimo recurso para aprender mais sobre aplicativos multi-contêiner.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!