O autor selecionou a United Nations Foundation para receber uma doação como parte do programa Write for DOnations.

A versão original deste tutorial para o WordPress foi escrita por Kathleen Juell.

Introdução

O Drupal é um sistema de gerenciamento de conteúdo (CMS) escrito em PHP e distribuído sob a Licença Pública Geral GNU de código aberto. Pessoas e organizações em todo mundo usam o Drupal para executar sites de governo, blogs pessoais, negócios, entre outros. O que torna o Drupal único entre outros frameworks CMS, é sua comunidade crescente e um conjunto de recursos que incluem processos seguros, desempenho confiável, modularidade e flexibilidade para se adaptar.

O Drupal requer a instalação da pilha LAMP (Linux, Apache, MySQL e PHP) ou LEMP (Linux, Nginx, MySQL, e PHP), mas a instalação de componentes individuais é uma tarefa que consome tempo. Podemos usar ferramentas como o Docker e o Docker Compose para simplificar o processo de instalação do Drupal. Este tutorial utilizará imagens do Docker para instalar componentes individuais dentro dos contêineres do Docker. Ao usar o Docker Compose, podemos definir e gerenciar vários contêineres para o banco de dados, a aplicação e a rede/comunicação entre eles.

Neste tutorial, instalaremos o Drupal usando o Docker Compose para que possamos aproveitar a containerização e fazer o deploy do nosso site Drupal em servidores. Vamos executar contêineres para um banco de dados MySQL, o servidor web Nginx e o Drupal. Também protegeremos nossa instalação, obtendo certificados TLS/SSL com o Let’s Encrypt para o domínio que queremos associar ao nosso site. Por fim, você irá configurar um cron job para renovar seus certificados para que seu domínio permaneça seguro.

Pré-requisitos

Para seguir este tutorial, vamos precisar do seguinte:

  • Um servidor executando o Ubuntu 18.04, junto com um usuário não-root com privilégios sudo e um firewall ativo. Para saber como configurar isso, consulte este guia de Configuração inicial do servidor.
  • O Docker instalado no seu servidor, de acordo com as instruções dos Passos 1 e 2 do tutorial sobre Como instalar e usar o Docker no Ubuntu 18.04. Este tutorial foi testado na versão 19.03.8.
  • O Docker Compose instalado no seu servidor, de acordo com as instruções do Passo 1 do tutorial sobre Como instalar o Docker Compose no Ubuntu 18.04. Este tutorial foi testado na versão 1.21.2.
  • Um nome de domínio registrado. Este tutorial utilizará your_domain durante todo o processo. 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:
    • Um registro A com your_domain apontando para o endereço IP público do seu servidor.
    • Um registro A com www.your_domain apontando para o endereço IP público do seu servidor.

Passo 1 — Definindo as configurações do servidor Web

Antes de executar quaisquer contêineres, precisamos definir a configuração para nosso servidor web Nginx. Nosso arquivo de configuração incluirá alguns blocos de localização específicos do Drupal, junto com um bloco de localização para direcionar solicitações de verificação do Let’s Encrypt para o cliente Certbot para a renovação automatizada de certificados.

Primeiro, vamos criar um diretório de projeto para nossa configuração do Drupal chamado drupal:

  • mkdir drupal

Vá para o diretório recém-criado:

  • cd drupal

Agora, podemos criar um diretório para nosso arquivo de configuração:

  • mkdir nginx-conf

Abra o arquivo com o nano ou com o seu editor favorito:

  • nano nginx-conf/nginx.conf

Neste arquivo, vamos adicionar um bloco de servidor com diretivas para o nosso nome de servidor e document root, e blocos de localização para direcionar os solicitações do cliente Certbot para os certificados, processamento PHP e solicitações de ativos estáticos.

Adicione o seguinte código ao arquivo. Certifique-se de substituir example.com pelo seu próprio nome de domínio:

~/drupal/nginx-conf/nginx.conf
server {
    listen 80;
    listen [::]:80;

    server_name your_domain www.your_domain;

    index index.php index.html index.htm;

    root /var/www/html;

    location ~ /.well-known/acme-challenge {
        allow all;
        root /var/www/html;
    }

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

    rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass drupal:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ /\.ht {
        deny all;
    }

    location = /favicon.ico {
        log_not_found off; access_log off;
    }
    location = /robots.txt {
        log_not_found off; access_log off; allow all;
    }
    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
        expires max;
        log_not_found off;
    }
}

Nosso bloco de servidor inclui as seguintes informações:

Directives:

  • listen: isso informa ao Nginx para escutar na porta 80, que nos permitirá usar o plug-in webroot do Certbot para nossas solicitações de certificados. Observer que não estamos incluindo a porta 443 ainda — atualizaremos nossa configuração para incluir SSL assim que tivermos tido sucesso na obtenção dos nossos certificados.

  • server_name: define nosso nome do servidor e o bloco de servidor que deve ser usado para solicitações feitas para o nosso servidor. Certifique-se de substituir example.com nesta linha pelo seu próprio nome de domínio.

  • index: a diretiva index define os arquivos que serão usados como índices durante o processamento das solicitações para o nosso servidor. Aqui, modificamos a ordem padrão de prioridade, movendo o index.php para frente do index.html, para que o Nginx priorize os arquivos chamados index.php quando possível.

  • root: nossa diretiva para root designa o diretório raiz para solicitações feitas ao nosso servidor. O diretório /var/www/html é criado como um ponto de montagem no momento da compilação através de instruções no nosso Dockerfile do Drupal. Essas instruções do Dockerfile também garantem que os arquivos da versão do Drupal estejam montados neste volume.

  • rewrite: se a expressão regular (^/core/authorize.php/core/authorize.php(.*)$) *)$) corresponde a uma solicitação URI, a URI é alterada conforme especificado na string de substituição (/core/authorize.php$1<^>).

Blocos de localização:

  • location ~ /.well-known/acme-challenge: este bloco de localização irá lidar com solicitações para o diretório .well-known, no qual o Certbot irá colocar um arquivo temporário para confirmar que o DNS do nosso domínio resolva para nosso servidor. Com esta configuração pronta, poderemos utilizar o plug-in webroot do Certbot para obter certificados para o nosso domínio.

  • location /: neste bloco de localização, usaremos uma diretiva try_files para verificar se há arquivos que correspondam às solicitações de URI individuais. Entretanto, em vez de retornar o status 404 Not Found como padrão, vamos passar o controle para o arquivo index.php do Drupal com os argumentos da solicitação.

  • location ~ \.php$: este bloco de localização irá lidar com o processamento PHP e fará um proxy dessas solicitações para o nosso contêiner drupal. Como nossa imagem Docker do Drupal se baseará na imagem php:fpm, também vamos incluir opções de configuração que são específicas para o protocolo FastCGI neste bloco. O Nginx requer um processador de PHP independente para as solicitações PHP: no nosso caso, estas solicitações serão tratadas pelo processador php-fpm, que está incluído na imagem php:fpm. Além disso, este bloco de localização inclui diretivas específicas do FastCGI, variáveis e opções que irão fazer proxy das solicitações para a aplicação do Drupal em execução no nosso contêiner Drupal, definir o index preferido em relação às solicitações de URI analisadas, e analisar as solicitações de URI.

  • location ~ /\.ht: este bloco irá lidar com arquivos .htaccess já que o Nginx não os servirá. A diretiva deny_all garante que os arquivos .htaccess nunca sejam exibidos em relação aos usuários.

  • location = /favicon.ico, location =/robots.txt: esses blocos garantem que os pedidos para o /favicon.ico e /robots.txt não serão registrados.

  • location ~* \.(css|gif|ico|jpeg|jpg|js|png)$: este bloco desativa o registro das solicitações de ativos estáticos e garante que esses ativos permaneçam altamente armazenáveis em cache, uma vez que são normalmente dispendiosos de serem exibidos.

Para obter mais informações sobre o FastCGI proxying, consulte o artigo Entendendo e implementando o uso de proxy com a FastCGI no Nginx. Para obter informações sobre servidor e blocos de localização, consulte o artigo Entendendo o servidor Nginx e os algoritmos de seleção de blocos de localização.

Salve e feche o arquivo quando você terminar a edição.

Com sua configuração do Nginx definida, podemos prosseguir e partir para a criação das variáveis de ambiente para passar para o seu aplicativo e para os contêineres de banco de dados no tempo de execução.

Passo 2 — Definindo as variáveis de ambiente

Nossa aplicação Drupal precisa de um banco de dados (MySQL, PostgresSQL, etc.) para salvar informações relacionadas ao site. O contêiner do Drupal precisará de acesso a certas variáveis de ambiente no ambiente de execução para acessar o contêiner de banco de dados (MySQL). Essas variáveis contêm as informações sensíveis como as credenciais do banco de dados. Assim, não podemos expô-las diretamente no arquivo do Docker Compose — o arquivo principal que contém informações sobre como nossos contêineres serão executados.

É sempre recomendado definir os valores sensíveis no arquivo .env e restringir sua circulação. Isso impedirá esses valores de serem copiados para os repositórios do nosso projeto e de ficarem expostos publicamente.

No diretório principal do projeto, ~/drupal, crie e abra um arquivo chamado .env:

  • nano .env

Adicione as seguintes variáveis ao arquivo .env, substituindo as seções destacadas pelas credenciais que você deseja usar:

~/drupal/.env
MYSQL_ROOT_PASSWORD=root_password
MYSQL_DATABASE=drupal
MYSQL_USER=drupal_database_user
MYSQL_PASSWORD=drupal_database_password

Agora incluímos uma senha para a conta administrativa root para o MySQL, assim como nosso nome de usuário e senha escolhidos para nosso banco de dados da aplicação.

Nosso arquivo .env contém informações sensíveis, portanto, é sempre recomendado incluí-las nos arquivos .gitignore e .dockerignore do projeto para que ele não seja adicionado em nossos repositórios Git e imagens do Docker.

Se você planeja trabalhar com o Git para controle de versão, inicialize o seu diretório de trabalho atual como um repositório com o git init:

  • git init

Abra o arquivo .gitignore:

  • nano .gitignore

Adicione o seguinte:

~/drupal/.gitignore
.env

Salve e saia do arquivo.

De maneira semelhante, abra o arquivo .dockerignore

  • nano .dockerignore

Adicione o seguinte:

~/drupal/.dockerignore
.env
.git

Salve e saia do arquivo.

Agora que tomamos medidas para proteger nossas credenciais como variáveis de ambiente, vamos seguir para nosso próximo passo de definição de nossos serviços em um arquivo docker-compose.yml.

Passo 3— Definindo serviços com o Docker Compose

O Docker Compose é uma ferramenta para definir e executar aplicações Docker multi-container. Definimos um arquivo YAML para configurar os serviços de nossa aplicação. Um service no Docker Compose é um contêiner em execução, e o Compose nos permite vincular esses serviços com volumes e redes compartilhados.

Criaremos diferentes contêineres para nossa aplicação Drupal, banco de dados e servidor web. Junto com esses, também criaremos um contêiner para executar o Certbot, para obter certificados para nosso servidor web.

Crie um arquivo docker-compose.yml:

  • nano docker-compose.yml

Adicione o seguinte código para definir a versão do arquivo Compose e o serviço de banco de dados mysql:

~/drupal/docker-compose.yml
version: "3"

services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: unless-stopped
    env_file: .env
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - internal

Vamos passar por esses um por um com todas as opções de configuração do serviço mysql:

  • image: especifica a imagem que será usada/baixada para criar o contêiner. É sempre recomendado usar a imagem com a tag de versão apropriada, excluindo a tag latest para evitar conflitos futuros. Leia mais em Melhores práticas do Dockerfile na documentação do Docker.

  • container_name: para definir o nome do contêiner.

  • command: isso é usado para sobrepor o comando padrão (instrução CMD) na imagem. O MySQL tem suportado diferentes plug-ins de autenticação, mas o mysql_native_password é o método tradicional para autenticar-se. Como o PHP e, portanto, o Drupal, não suportam a autenticação MySQL mais nova precisamos definir o --default-authentication-plugin=mysql_native_password como o mecanismo de autenticação padrão.

  • restart: isso é usado para definir a política de reinicialização do contêiner. A política unless-stopped reinicia um contêiner, a menos que ele seja interrompido manualmente.

  • env_file: isso adiciona as variáveis de ambiente a partir de um arquivo. Em nosso caso, ele irá ler as variáveis de ambiente do arquivo .env, definidas no passo anterior.

  • volumes: isso monta os caminhos de host ou volumes nomeados, especificados como subopções para um serviço. Estamos montando um volume nomeado chamado db-data no diretório /var/lib/mysql no contêiner, onde o MySQL por padrão irá escrever seus arquivos de dados.

  • networks: define a rede internal à qual nosso serviço de aplicação se juntará. Vamos definir as redes no final do arquivo.

Criamos nossa definição de serviço mysql. Dessa forma, vamos adicionar a definição do serviço de aplicação drupal ao final do arquivo:

~/drupal/docker-compose.yml
...
  drupal:
    image: drupal:8.7.8-fpm-alpine
    container_name: drupal
    depends_on:
      - mysql
    restart: unless-stopped
    networks:
      - internal
      - external
    volumes:
      - drupal-data:/var/www/html

Nessa definição de serviço, estamos nomeando nosso contêiner e definindo uma política de reinicialização, como fizemos com o serviço mysql. Também estamos adicionando algumas opções específicas para este contêiner:

  • image: aqui, estamos usando a imagem Drupal 8.7.8-fpm-alpine. Esta imagem tem o processador php-fpm que nosso servidor web Nginx requer para lidar com o processamento PHP. Além disso, estamos usando a imagem alpine, derivada do projeto Linux alpine, que diminuirá o tamanho global da imagem e é recomendado nas melhores práticas do Dockerfile. O Drupal tem mais versões de imagens, por isto, verifique-as no Dockerhub.

  • depends_on: isso é usado para expressar dependência entre serviços. Definir o serviço mysql, como a dependência para nosso contêiner drupal, garantirá que nosso contêiner drupal seja criado após o contêiner mysql e permitirá que nossa aplicação inicie sem problemas.

  • networks: aqui, adicionamos este contêiner à rede external juntamente com a rede internal. Isso garantirá que nosso serviço mysql esteja acessível apenas a partir do contêiner drupal através da rede internal enquanto mantém esse contêiner acessível para outros contêineres através da rede external.

  • volumes: estamos montando um volume nomeado chamado drupal-data no ponto de montagem /var/www/html criado pela imagem Drupal. Usar um volume nomeado dessa maneira nos permitirá compartilhar o código do nosso aplicativo com outros contêineres.

Em seguida, vamos adicionar a definição de serviço do Nginx após a definição do serviço drupal:

~/drupal/docker-compose.yml
...
  webserver:
    image: nginx:1.17.4-alpine
    container_name: webserver
    depends_on:
      - drupal
    restart: unless-stopped
    ports:
      - 80:80
    volumes:
      - drupal-data:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - external

Novamente, estamos nomeando nosso contêiner e tornando-o dependente do contêiner Drupal em ordem de inicialização. Também estamos usando uma imagem alpine — a imagem Nginx 1.17.4-alpine

Essa definição de serviço também inclui as seguintes opções:

  • ports: expõe a porta 80 para habilitar as opções de configuração que definimos no nosso arquivo nginx.conf no Passo 1.

  • volumes: aqui, estamos definindo tanto o volume nomeado como o caminho do host:

    • drupal-data:/var/www/html: isso irá montar o código de nossa aplicação Drupal no diretório /var/www/html - que definimos como a raiz no bloco de servidor do Nginx.
    • ./nginx-conf:/etc/nginx/conf.d: isso irá montar o diretório de configuração do Nginx no host no diretório relevante no contêiner, garantindo que quaisquer alterações que fizermos em arquivos no host serão refletidas no contêiner.
    • certbot-etc:/etc/letsencrypt: isso irá montar os certificados e chaves relevantes do Let’s Encrypt para o nosso domínio no diretório apropriado no contêiner.
    • networks: definimos a rede external apenas para permitir que este contêiner se comunique com o contêiner drupal e não com o contêiner mysql.

Por fim, adicionaremos nossa última definição de serviço para o serviço certbot. Certifique-se de substituir sammy@your_domain e your_domain pelo seu próprio e-mail e nome de domínio:

~/drupal/docker-compose.yml
...
  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - drupal-data:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain

Essa definição diz ao Compose para obter a imagem certbot/certbot do Docker Hub. Ela também usa volumes nomeados para compartilhar recursos com o contêiner do Nginx, incluindo certificados de domínio e chave em certbot-etc e o código da aplicação em drupal-data

Também usamos o depends_on para garantir que o contêiner certbot seja iniciado depois que o serviço webserver estiver em execução.

Nós não especificamos nenhuma rede aqui, pois este contêiner não se comunicará com nenhum serviço através da rede. Ela está adicionando apenas os certificados de domínio e a chave, que montamos usando os volumes nomeados.

Também incluímos a opção command que especifica um subcomando para executar com o comando certbot padrão do contêiner. O cliente Certbot suporta plug-ins para obter e instalar certificados. Estamos usando o plug-in webroot para obter um certificado, incluindo certonly e --webroot na linha de comando. Leia mais sobre o plug-in e comandos adicionais na Documentação oficial do Certbot.

Após a definição do serviço do certbot, adicione as definições de rede e de volume:

~/drupal/docker-compose.yml
...
networks:
  external:
    driver: bridge
  internal:
    driver: bridge

volumes:
  drupal-data:
  db-data:
  certbot-etc:

A chave de nível superior networks nos permite especificar redes para serem criadas. networks permite a comunicação através dos serviços/contêineres em todas as portas, uma vez que eles estão no mesmo host do Docker daemon. Definimos duas redes, internal e external, para proteger a comunicação do servidor web, drupal e serviços mysql.

A chave volumes é usada para definir os volumes nomeados drupal-data, db-data e certbot-etc. Quando o Docker cria volumes, o conteúdo do volume é armazenado em um diretório do sistema de arquivos do host, /var/lib/docker/volumes/, que é gerenciado pelo Docker. O conteúdo de cada volume é então montado deste diretório para qualquer contêiner que utilize o volume. Dessa forma, é possível compartilhar código e dados entre os contêineres.

O arquivo final docker-compose.yml ficará parecido com o seguinte:

~/drupal/docker-compose.yml
version: "3"

services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: unless-stopped
    env_file: .env
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - internal

  drupal:
    image: drupal:8.7.8-fpm-alpine
    container_name: drupal
    depends_on:
      - mysql
    restart: unless-stopped
    networks:
      - internal
      - external
    volumes:
      - drupal-data:/var/www/html

  webserver:
    image: nginx:1.17.4-alpine
    container_name: webserver
    depends_on:
      - drupal
    restart: unless-stopped
    ports:
      - 80:80
    volumes:
      - drupal-data:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - external

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - drupal-data:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain

networks:
  external:
    driver: bridge
  internal:
    driver: bridge

volumes:
  drupal-data:
  db-data:
  certbot-etc:

Terminamos de definir nossos serviços. Em seguida, vamos iniciar o contêiner e testar nossas solicitações de certificados.

Passo 4 — Obtendo certificados e credenciais SSL

Podemos iniciar nossos contêineres com o comando docker-compose up, que criará e executará nossos contêineres na ordem que especificamos. Se nossas solicitações de domínio forem bem sucedidas, veremos o status de saída correto em nossa saída e os certificados corretos montados na pasta /etc/letsencrypt/live no contêiner do webserver.

Para executar os contêineres em segundo plano, use o comando docker-compose up com a flag -d:

  • docker-compose up -d

Você verá uma saída semelhante confirmando que seus serviços foram criados:

Output
... Creating mysql ... done Creating drupal ... done Creating webserver ... done Creating certbot ... done

Verifique o status dos serviços usando o comando docker-compose ps:

  • docker-compose ps

Vamos ver os serviços mysql, drupal e webserver com State de Up, enquanto o certbot sairá com uma mensagem de status 0:

Output
Name Command State Ports -------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 drupal docker-php-entrypoint php-fpm Up 9000/tcp mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp

Se você vir qualquer outra coisa além de Up na coluna State em relação aos serviços mysql, drupal ou webserver, ou um status de saída que não seja 0 para o contêiner certbot, certifique-se de verificar os logs de serviço com o comando docker-compose logs:

  • docker-compose logs service_name

Agora, podemos verificar os nossos certificados montados no contêiner webserver usando o comando docker-compose ​​exec:

  • docker-compose exec webserver ls -la /etc/letsencrypt/live

Isso dará o seguinte resultado:

Output
total 16 drwx------ 3 root root 4096 Oct 5 09:15 . drwxr-xr-x 9 root root 4096 Oct 5 09:15 .. -rw-r--r-- 1 root root 740 Oct 5 09:15 README drwxr-xr-x 2 root root 4096 Oct 5 09:15 your_domain

Agora que tudo funciona com sucesso, podemos editar nossa definição de serviço do certbot para remover a flag --staging

Abra o arquivo docker-compose.yml,vá para a definição de serviço do certbot e substitua a flag --staging na opção command pela flag --force-renewal, que dirá ao Certbot que você quer solicitar um novo certificado com os mesmos domínios de um certificado existente. A definição atualizada do certbot se parecerá com isto:

~/drupal/docker-compose.yml
...
  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - drupal-data:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain
...

Precisamos executar o docker-compose up novamente para recriar o contêiner certbot. Também vamos incluir a opção --no-deps para dizer ao Compose que ele pode ignorar a inicialização do serviço webserver, já que ele já está em execução:

  • docker-compose up --force-recreate --no-deps certbot

Você verá a saída indicando que sua solicitação de certificado foi bem-sucedida:

Output
Recreating certbot ... done Attaching to certbot certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log certbot | Plugins selected: Authenticator webroot, Installer None certbot | Renewing an existing certificate certbot | Performing the following challenges: certbot | http-01 challenge for your_domain certbot | http-01 challenge for www.your_domain certbot | Using the webroot path /var/www/html for all unmatched domains. certbot | Waiting for verification... certbot | Cleaning up challenges certbot | IMPORTANT NOTES: certbot | - Congratulations! Your certificate and chain have been saved at: certbot | /etc/letsencrypt/live/your_domain/fullchain.pem certbot | Your key file has been saved at: certbot | /etc/letsencrypt/live/your_domain/privkey.pem certbot | Your cert will expire on 2020-01-03. 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

Agora que geramos nossos certificados com sucesso, podemos atualizar nossa configuração do Nginx para incluir SSL.

Passo 5 — Modificando a configuração do servidor Web e da definição de serviço

Após instalar certificados SSL no Nginx, precisaremos redirecionar todas as solicitações HTTP para o HTTPS. Também teremos que especificar nosso certificado SSL e localizações de chaves e adicionar parâmetros de segurança e cabeçalhos.

Como você vai recriar o serviço webserver para incluir essas adições, você pode interrompê-lo agora:

  • docker-compose stop webserver

Isso dará o seguinte resultado:

Output
Stopping webserver ... done

Em seguida, vamos remover o arquivo de configuração do Nginx que criamos anteriormente:

  • 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 example.com pelo seu próprio domínio:

~/drupal/nginx-conf/nginx.conf
server {
    listen 80;
    listen [::]:80;

    server_name your_domain www.your_domain;

    location ~ /.well-known/acme-challenge {
        allow all;
        root /var/www/html;
    }

    location / {
        rewrite ^ https://$host$request_uri? permanent;
    }
}
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name your_domain www.your_domain;

    index index.php index.html index.htm;

    root /var/www/html;

    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem;

    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;

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

    rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass drupal:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ /\.ht {
        deny all;
    }

    location = /favicon.ico {
        log_not_found off; access_log off;
    }
    location = /robots.txt {
        log_not_found off; access_log off; allow all;
    }
    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
        expires max;
        log_not_found off;
    }
}

O bloco de servidor HTTP especifica o plug-in webroot para as solicitações de renovação do Certbot para o diretório .well-known/acme-challenge. Isso também inclui uma diretiva de reescrita, que direciona as solicitações 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 faz a iteração nos protocolos HTTP e os benefícios que ele pode ter para o desempenho do site, consulte a introdução sobre Como configurar o Nginx com suporte do HTTP/2 no Ubuntu 18.04.

Esses blocos habilitam o SSL, pois incluímos nosso certificado SSL e localizações de chaves, junto com os cabeçalhos recomendados. Esses cabeçalhos nos habilitarão a obter uma classificação A nos sites de teste de servidores SSL Labs e Security Headers

Nossas diretivas root e index também estão localizadas neste bloco, assim como o resto dos blocos de localização específicos do Drupal discutidos no Passo 1.

Salve e feche o arquivo de configuração atualizado do Nginx.

Antes de recriar o contêiner webserver, precisaremos adicionar um mapeamento de porta 443 na definição de serviço webserver, pois habilitamos certificados SSL.

Abra o arquivo docker-compose.yml:

  • nano docker-compose.yml

Faça as seguintes alterações na definição de serviço webserver:

~/drupal/docker-compose.yml
...
  webserver:
    image: nginx:1.17.4-alpine
    container_name: webserver
    depends_on:
      - drupal
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - drupal-data:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - external
...

Após habilitar os certificados SSL, nosso docker-compose.yml se parecerá com isto:

~/drupal/docker-compose.yml
version: "3"

services:
  mysql:
    image: mysql:8.0
    container_name: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: unless-stopped
    env_file: .env
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - internal

  drupal:
    image: drupal:8.7.8-fpm-alpine
    container_name: drupal
    depends_on:
      - mysql
    restart: unless-stopped
    networks:
      - internal
      - external
    volumes:
      - drupal-data:/var/www/html

  webserver:
    image: nginx:1.17.4-alpine
    container_name: webserver
    depends_on:
      - drupal
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
    volumes:
      - drupal-data:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - external

  certbot:
    depends_on:
      - webserver
    image: certbot/certbot
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - drupal-data:/var/www/html
    command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain

networks:
  external:
    driver: bridge
  internal:
    driver: bridge

volumes:
  drupal-data:
  db-data:
  certbot-etc:

Salve e feche o arquivo. Vamos recriar o serviço webserver com nossa configuração atualizada:

  • docker-compose up -d --force-recreate --no-deps webserver

Isso dará o seguinte resultado:

Output
Recreating webserver ... done

Verifique seus serviços com o docker-compose ps:

  • docker-compose ps

Você verá os serviços mysql, drupal e webserver como UP enquanto o certbot sairá com uma mensagem de status 0:

Output
Name Command State Ports -------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 drupal docker-php-entrypoint php-fpm Up 9000/tcp mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

Agora, todos os nossos serviços estão em execução e estamos prontos para seguir com a instalação do Drupal através da interface web.

Passo 6 — Concluindo a instalação através da Interface com a Web

Vamos completar a instalação através da interface web do Drupal.

Em um navegador web, navegue até o domínio do servidor. Lembre-se de substituir example.com aqui com seu próprio nome de domínio:

https://your_domain

Selecione a linguagem para usar:

Choose language page on Drupal web interface

Clique em Save and continue Vamos parar na página Installation profile O Drupal tem vários perfis, então selecione o perfil Standard e clique em Save and continue.

Choose profile page on Drupal web interface

Após selecionar o perfil, vamos seguir adiante para a página Database configuration Selecione o tipo de banco de dados como MySQL, MariaDB, Percona Server, or equivalent e digite os valores do Database name, username, e password a partir dos valores correspondentes ao MYSQL_DATABASE, MYSQL_USER, e MYSQL_PASSWORD respectivamente, definidos no arquivo .env no Passo 2. Clique em Advanced Options e defina o valor do Host para o nome do contêiner do serviço mysql. Clique em Save and continue

Set up database page on Drupal web interface

Após configurar o banco de dados, ele começará a instalar módulos e temas padrão do Drupal:

Install site page on Drupal web interface

Assim que o site for instalado, vamos até a página de configuração de site do Drupal para a configuração do nome do site, e-mail , nome de usuário, senha, e configurações regionais. Preencha as informações e clique em Save and continue:

Configure site page on Drupal web interface

Após clicar em Save and continue, podemos ver a página Welcome to Drupal, que mostra que nosso site Drupal está funcionando com sucesso.

Welcome to Drupal page on Drupal web interface

Agora que nossa instalação do Drupal está completa, precisamos garantir que nossos certificados SSL se renovem automaticamente.

Passo 7 — Renovando certificados

Os certificados do Let’s Encrypt são válidos por 90 dias, de modo que você vai querer configurar um processo de renovação automatizado para garantir que eles não expirem. Uma maneira de fazer isso é criando um job com o utilitário de agendamento cron. Neste caso, vamos criar uma tarefa do cron para executar periodicamente um script que renovará nossos certificados e recarregará nossa configuração do Nginx.

Vamos criar o arquivo ssl_renew.sh para renovar nossos certificados:

  • nano ssl_renew.sh

Adicione o código a seguir: Lembre-se de substituir o nome do diretório pelo seu próprio usuário não-root:

~/drupal/ssl_renew.sh

#!/bin/bash

cd /home/sammy/drupal/
/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew --dry-run && \
/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver

Este script muda para o diretório ~/drupal do projeto e executa os comandos docker-compose a seguir:

  • 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.

Feche o arquivo e torne-o executável executando o seguinte comando:

  • sudo chmod +x ssl_renew.sh

Em seguida, abra seu arquivo de crontab do root para executar o script de renovação em um intervalo especificado:

  • sudo crontab -e

Se essa é a primeira vez que você edita este arquivo, você será solicitado a escolher um editor de texto com o qual abrirá o arquivo:

Output
no crontab for root - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/nano 2. /usr/bin/vim.basic 3. /usr/bin/vim.tiny 4. /bin/ed Choose 1-4 [1]: ...

No final do arquivo, adicione a seguinte linha, substituindo sammy pelo seu nome de usuário:

crontab
...
*/5 * * * * /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1

Isso definirá o intervalo do job para cada cinco minutos, para que possamos testar se a sua solicitação de renovação funcionou como previsto. Também criamos um arquivo de registro, cron.log, para gravar o resultado relevante do trabalho.

Após cinco minutos, use o comando tail para verificar o cron.log para ver se a solicitação de renovação foi ou não foi bem sucedida:

  • tail -f /var/log/cron.log

Você verá uma saída confirmando uma renovação com sucesso:

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/your_domain/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Pressione CTRL+C para sair do processo do tail.

Agora, podemos modificar o arquivo crontab para executar o script cada segundo dia da semana, às 2 AM. Altere a linha final do crontab para o seguinte:

crontab
...
* 2 * * 2 /home/sammy/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1

Saia e salve o arquivo.

Agora, vamos remover a opção --dry-run do script ssl_renew.sh Primeiro, abra-o:

  • nano ssl_renew.sh

Em seguida, mude o conteúdo para o seguinte:

~/drupal/ssl_renew.sh
#!/bin/bash

cd /home/sammy/drupal/
/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew && \
/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver

Agora, nosso cron job cuidará da expiração de nossos certificados SSL, renovando-os quando eles forem elegíveis.

Conclusão

Neste tutorial, você usou o Docker Compose para criar uma instalação do Drupal com um servidor web Nginx. Como parte deste fluxo de trabalho, obtivemos certificados TLS/SSL para o domínio que queríamos associado ao nosso site Drupal e criamos um cron job para renovar esses certificados quando necessário.

Se você quiser aprender mais sobre o Docker, verifique nossa página de tópicos do Docker.

0 Comments

Creative Commons License