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.
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.
Para seguir este tutorial, vamos precisar do seguinte:
sudo
e um firewall ativo. Para saber como configurar isso, consulte este guia de Configuração inicial do servidor.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.your_domain
apontando para o endereço IP público do seu servidor.www.your_domain
apontando para o endereço IP público do seu servidor.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:
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.
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:
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:
.env
Salve e saia do arquivo.
De maneira semelhante, abra o arquivo .dockerignore
- nano .dockerignore
Adicione o seguinte:
.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
.
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
:
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:
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
:
...
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:
...
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:
...
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:
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.
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:
Outputtotal 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:
...
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:
OutputRecreating 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.
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:
OutputStopping 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:
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
:
...
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:
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:
OutputRecreating 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.
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:
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.
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
Após configurar o banco de dados, ele começará a instalar módulos e temas padrão do Drupal:
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:
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.
Agora que nossa instalação do Drupal está completa, precisamos garantir que nossos certificados SSL se renovem automaticamente.
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:
#!/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:
Outputno 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:
...
*/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:
...
* 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:
#!/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.
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.
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!