Introdução
WordPress é um dos Sistemas de Gerenciamento de Conteúdo (CMSs) mais populares do mercado. Estatisticamente, ele alimenta mais de 39% de todos os sites que você vê na rede mundial de computadores. É uma escolha popular devido à sua extensibilidade por meio de plugins e ao seu sistema flexível de templates. Ele permite que você altere sua aparência em segundos. Além disso, sua administração pode ser feita através da interface web sem exigir muito conhecimento técnico.
Além disso, o WordPress é gratuito e de código aberto e é construído sobre um banco de dados MySQL com processamento PHP. Você pode implantar o WordPress em uma pilha LAMP (Linux, Apache, MySQL e PHP) ou em uma pilha LEMP (Linux, Nginx, MySQL e PHP). No entanto, configurar a pilha toda vez que você deseja implantar consome muito tempo.
Felizmente, métodos modernos de entrega de software, como computação em nuvem, Docker, e Docker Compose suavizaram a experiência geral do desenvolvedor. Essas ferramentas simplificam o processo de configuração de qualquer pilha, evitando a sobrecarga de instalar e configurar componentes individuais toda vez que você deseja implantar um aplicativo. Em vez disso, você escreve arquivos de configuração que serão usados para baixar e criar imagens e executá-las em contêineres Docker, permitindo que você implante seu aplicativo com apenas um comando.
Contêineres são ambientes padronizados leves, virtualizados, portáteis e definidos por software que permitem que o software seja executado de forma isolada de outros softwares em execução na máquina host física. O Docker Compose permite gerenciar múltiplos contêineres e garantir que eles se comuniquem. Por exemplo, o código-fonte de um aplicativo e um banco de dados devem se comunicar.
Neste tutorial, nós iremos construir uma aplicação WordPress multicontêiner. Um aplicativo WordPress completo requer três contêineres: banco de dados MySQL, servidor Nginx e código-fonte do WordPress. Sendo a segurança uma prioridade nos sites modernos, obteremos um certificado SSL da Let’s Encrypt para proteger sua instalação. Em seguida, configuraremos uma tarefa cron para verificar e renovar periodicamente os certificados, de modo que a segurança do seu site seja mantida continuamente.
Pré-requisitos
- Como este é um tutorial prático, você deve ter uma instalação do Ubuntu 20.04 como seu ambiente operacional inicial. Você também deve ter um usuário não-root com privilégios sudo. Aqui está um tutorial passo a passo para ajudá-lo a configurar seu servidor Ubuntu.
- Você também precisa instalar o Docker. Você pode consultar este tutorial sobre como instalar e operar o Docker no Ubuntu 18.04.
- Uma instalação do Docker Compose. Você pode seguir a Etapa 1 do tutorial Como Instalar e Configurar o Docker Compose no Ubuntu 20.04.
- Um nome de domínio registrado é necessário para obter um certificado TLS/SSL da Let’s Encrypt. Para fins deste tutorial, usaremos
example.com. - Configure os registros DNS para apontar o tráfego para o seu VPS. Você precisa de dois registros DNS:
- Um registro A com
example.comapontando para o endereço IP público do seu servidor. - Um registro A com
www.example.comapontando para o endereço IP público do seu servidor.
- Um registro A com
Etapa 1: Definir as Configurações para o Servidor Web
O servidor web armazena os arquivos do seu site e permite que os usuários acessem sua aplicação web. Portanto, é apropriado que na primeira etapa definamos a configuração para o servidor web. Estaremos definindo um arquivo de configuração do servidor Nginx que incluirá blocos de localização específicos do WordPress. Também incluiremos blocos de localização para direcionar as solicitações de verificação do Let’s Encrypt para o cliente Certbot para renovações automáticas do certificado.
Vamos começar criando um diretório para o projeto. Você pode escolher o nome de diretório que preferir. Usaremos wordpress_docker para este tutorial. Digite o seguinte comando para criar o diretório e navegar até ele:
|
1 |
mkdir wordpress_docker && cd wordpress_docker |
Em seguida, crie um diretório para conter os arquivos de configuração do Nginx com o comando:
|
1 |
mkdir nginx-conf |
Use nano para abrir o arquivo com o seguinte comando:
|
1 |
nano nginx-conf/nginx.conf |
Neste arquivo, definiremos as diretivas básicas para uma configuração de bloco de servidor Nginx. Elas incluem diretivas para o nome do servidor, raiz do documento e blocos de localização para direcionar as solicitações do plugin Certbot para certificados, arquivos estáticos e processamento PHP. Você pode ler nosso tutorial sobre Como Proteger o Nginx com Let’s Encrypt para saber mais. Adicione o seguinte código ao arquivo, substituindo example.com pelo seu nome de domínio registrado:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
server { listen 80; listen [::]:80; server_name example.com www.example.com; 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; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app: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; } } |
Vamos definir as seções que você adicionou:
-
Diretivas:
listen: diz ao Nginx para escutar na porta80. Isso permite o uso do webroot do Certbot para fazer solicitações de certificado. Assim que obtivermos um certificado SSL, atualizaremos esta configuração para usar a porta443.server_name: isso define o domínio para o qual esta configuração deve responder. O tráfego para o nome de domínio definido aqui será direcionado para este bloco de servidor específico e, portanto, para o documentoroot.root: define o diretório raiz para solicitações ao nome de domínio acima. Geralmente é o diretório que contém os arquivos reais do nosso site. Definimos o diretório para este/var/www/html. Ele será criado como um ponto de montagem do Docker durante o tempo de construção do contêiner. Definiremos as instruções para este processo dentro do WordPress Dockerfile.index: isso define os arquivos que serão usados como índices ou o ponto de entrada para o seu servidor web ao processar requisições. Movemos o index.php antes do index.html para que o Nginx priorize oindex.php.
-
Location Blocks:
location ~ /.well-known/acme-challenge: trata requisições para o diretório well-known onde o Certbot adiciona um arquivo temporário para validar que o DNS para o domínio especificado aponta para o servidor específico do qual estamos solicitando os certificados SSL. É por isso que você deve adicionar um domínio válido para que esta etapa funcione, em vez doexample.comque estamos usando neste tutorial.location /: captura requisições URI e dá o controle ao WordPressindex.phppara solicitar argumentos para processamento.location ~ \.php$: trata o processamento PHP e passa a requisição para o contêiner do WordPress (definiremos um arquivo de configuração para isso em uma etapa posterior). Definimos configurações específicas para o protocolo FastCGI aqui porque a imagem Docker do WordPress será baseada na imagem php:fpm. O Nginx usa um processador PHP independente para requisições específicas de PHP. Usaremos o processadorphp-fpmque vem com a imagem Dockerphp:fpm.location ~ /\.ht: trata arquivos.htaccessque o Nginx não usa. A diretivadeny allgarante que esses arquivos nunca sejam servidos aos visitantes do site.location = /favicon.ico, location = /robots.txt: como visto na definição, isso evita o registro de requisições para os arquivos/favicon.icoe/robots.txtfiles.location ~* \.(css|gif|ico|jpeg|jpg|js|png)$: desativa o registro de requisições para arquivos estáticos e garante que eles sejam armazenados em cache para diminuir a carga no servidor.
Agora você pode salvar e fechar o arquivo pressionando CTRL+X, Y, depois ENTER. Isso conclui a primeira etapa.
Step 2: Define Environment Variables
As variáveis de ambiente são necessárias para facilitar a comunicação entre a aplicação WordPress e o banco de dados. Elas também garantem que os dados da aplicação sejam persistidos. As variáveis de ambiente incluem informações confidenciais, como credenciais do banco de dados, e informações não confidenciais, como o nome do banco de dados e o host.
Por motivos de segurança, é sempre uma boa ideia não adicionar informações confidenciais aos repositórios do projeto. Portanto, em vez de definir os valores confidenciais no arquivo Docker Compose, definiremos as credenciais do MySQL dentro do arquivo .env que não será enviado ao repositório do projeto, correndo o risco de exposição pública. Dentro da raiz do projeto root ~/wordpress_docker abra o arquivo .env:
|
1 |
nano .env |
|
1 2 3 |
MYSQL_ROOT_PASSWORD=your_strong_root_password MYSQL_USER=your_wordpress_database_user MYSQL_PASSWORD=strong_wordpress_database_password |
A próxima coisa que você deve fazer é adicionar o arquivo .env aos arquivos .gitignore e .dockerignore para garantir que ele não seja adicionado aos seus repositórios ou imagens Docker, respectivamente.
Isso não é necessário para este tutorial, mas se você quiser trabalhar com o Git para controle de versão, insira o seguinte comando para inicializar o diretório atual como um repositório git:
|
1 |
git init |
Abra o .gitignore com o nano:
|
1 |
nano .gitignore |
Adicione a seguinte linha:
|
1 |
.env |
Salve e feche o arquivo. Em seguida, abra o .dockerignore com o nano:
|
1 |
nano .dockerignore |
Adicione a seguinte linha:
|
1 |
.env |
Aproveitando, você pode opcionalmente adicionar outros arquivos e diretórios associados ao desenvolvimento da sua aplicação:
|
1 2 3 |
.env .git docker-compose.yml |
Salve e feche o arquivo quando terminar. Isso é tudo para esta etapa. Vamos passar para a definição do Docker Compose.
Etapa 3: Configurar Serviços com o Docker Compose
O Docker Compose usa um docker-compose.yml arquivo para construir imagens. Este arquivo contém definições de serviço para a configuração completa de uma aplicação. As definições de serviço são basicamente instruções de como um contêiner será executado. Um serviço é um contêiner real em execução.
O Docker Compose torna possível definir diferentes serviços para aplicações multi-contêiner, vinculando os vários serviços entre si com redes e volumes compartilhados. Você verá isso em ação, pois definiremos três contêineres para nossa aplicação: servidor web, instalação do WordPress e banco de dados. Adicionaremos um quarto contêiner para executar o cliente Certbot para renovações de certificados.
Insira o seguinte comando para criar o docker-compose.yml arquivo:
|
1 |
nano docker-compose.yml |
A primeira linha em um docker-compose.yml arquivo é a definição de versão linha. Nós definimos 3 para a nossa. Depois, você pode começar a definir seus serviços. Adicione o seguinte trecho de código no arquivo para definir o db serviço:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
version: '3' services: #Serviço MySQL db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network |
Vamos discutir o que temos nas definições do serviço db abaixo:
image: determina a imagem na qual o contêiner será baseado. É sempre melhor especificar uma versão específica (mysql:8.0) do que usar a tag latest (mysql:latest) pois versões futuras de imagens do MySQL podem entrar em conflito com nossa aplicação se por acaso reconstruirmos esta imagem. Você pode encontrar mais informações sobre as Melhores práticas de Dockerfiles na documentação oficial do Dockerfile.container_name: especificamos o nome do contêiner aqui.restart: esta diretiva determina o comportamento de reinicialização do contêiner. O padrão énomas nós a definimos para semprereiniciara menos que seja parado manualmente.env_file: esta diretiva é usada para especificar a localização do arquivo com as variáveis de ambiente (.env) usadas pela nossa aplicação.environment: usada para especificar variáveis de ambiente adicionais. Neste tutorial, especificamos a variávelMYSQL_DATABASEpara conter o nome do banco de dados da nossa aplicação. O nome do banco de dados pode ser incluído nodocker-compose.yml.volumes: usado para especificar locais de montagem. No nosso exemplo, montamos um volume nomeado chamado dbdata no diretório/var/lib/mysqldo contêiner, que geralmente é o diretório de dados padrão do MySQL.command: esta diretiva especifica um comando que substituirá a instrução CMD padrão da imagem. Adicionamos uma opção ao comando padrãomysqldda imagem Docker que inicia o servidor MySQL dentro do contêiner. A opção que adicionamos é--default-authentication-plugin=mysql_native_password, que atualiza o plugin de autenticação padrão do MySQL para usar autenticação por senha (mysql_native_password). Isso é necessário para que o seu PHP (aplicação WordPress funcione) porque eles usam um nome de usuário e senha para acessar o banco de dados. Em versões mais recentes do MySQL, o plugin de autenticação padrão mudou. No entanto, a maioria das aplicações usa autenticação por senha. Portanto, você deve alterar essa configuração para que a aplicação funcione.networks: esta diretiva é usada para especificar que o serviçodbdeve se juntar àapp-network, que definiremos ao longo do tutorial.
A seguir, vamos definir a configuração de serviço para a nossa aplicação WordPress. Chamaremos o serviço e container_name de app. Adicione o seguinte trecho de código abaixo da db definição de serviço, tendo em mente a indentação correta:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#Serviço de código da aplicação WordPress app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network |
Assim como fizemos com o db serviço, nomeamos nosso container e definimos a política de reinicialização. Mais algumas opções que adicionamos estão definidas abaixo:
depends_on: esta diretiva garante que os containers sejam iniciados em ordem de dependência. No nosso caso, oappcontainer depende dodbcontainer. Portanto, ele será iniciado após odbcontainer ter sido iniciado. Isso precisa acontecer nesta ordem porque a aplicação WordPress depende da disponibilidade de um banco de dados MySQL para funcionar.image: como visto no trecho de código, usaremos a WordPress versão 5.1.1 fpm alpine imagem. Nós explicamos sobre o processadorphp-fpmque o Nginx requer para o processamento PHP. Esta imagem cuida disso. A imagem alpine baseada no projeto Alpine Linux ajuda a manter o tamanho da imagem menor. Se precisar de mais informações sobre variações de imagem, você pode seguir este link para imagens do WordPress no Docker Hub.env_file: especifica a localização do arquivo.envque contém as credenciais do banco de dados.environment: esta diretiva define variáveis de ambiente adicionais. No nosso caso, estamos definindo as variáveis que o WordPress espera e atribuindo a elas os valores das variáveis do nosso arquivo.env. Elas sãoWORDPRESS_DB_USER,WORDPRESS_DB_PASSWORD, eWORDPRESS_DB_HOSTque se refere ao servidor MySQL em execução no containerdb, acessível a partir da porta padrão do MySQL3306. Finalmente, você vê oWORDPRESS_DB_NAMEque definimos como WordPress. O mesmo valor é especificado na definição do serviço MySQL no container db:MYSQL_DATABASE=wordpress.volumes: esta diretiva monta um volume chamado app no ponto de montagem/var/www/html, criado pela imagem do WordPress. A nomeação de volumes permite o compartilhamento de código de aplicação com outros containers.networks: finalmente, adicionamos o container app àapp-networkpara garantir que ele se comunique com outros containers na rede.
Isso é tudo para o container de serviço app para a imagem do WordPress. Vamos agora definir o serviço webserver para a imagem do Nginx. Primeiro, adicione o seguinte trecho de código abaixo da definição do serviço app no seu arquivo docker-compose.yml :
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#Serviço de servidor web Nginx webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
Nós já explicamos a opção depends_on. No caso deste serviço webserver, o container será iniciado após o container app ter sido iniciado. O container do servidor web é baseado na imagem alpine do Nginx. Ele tem uma política de reinicialização semelhante às definições de serviço anteriores. As outras opções na definição do serviço webserver incluem:
ports: vincula as portas entre a máquina hospedeira e o contêiner. No Passo 1, tínhamos definido a porta80no arquivonginx.conf. Esta porta está mapeada para a porta80no contêiner.volumes: temos uma combinação de montagens de vínculo (bind mounts) e volumes nomeados sob esta opção:app:/var/www/html: esta definição de volume monta a aplicação WordPress no diretório/var/www/htmlque, anteriormente, havíamos definido como raiz no bloco de servidor do Nginx../nginx-conf:/etc/nginx/conf.d: esta definição faz a montagem de vínculo (bind mount) do diretório de configuração do Nginx na máquina hospedeira para o diretório de configuração do Nginx que definimos para o contêiner. Portanto, quaisquer alterações na máquina hospedeira são refletidas automaticamente no contêiner.certbot-etc:/etc/letsencrypt: esta definição monta os certificados e chaves do Let’s Encrypt para o domínio no diretório apropriado no contêiner.
networks: como nas definições de serviço anteriores, a diretivanetworksadiciona o serviço webserver àapp-networks.
Como terminamos com a definição do webserver, vamos adicionar instruções para o serviço Certbot. Isso cuidará da obtenção dos seus certificados TLS/SSL do Let’s Encrypt. Se você quiser saber mais sobre como proteger um servidor Nginx, este tutorial sobre como proteger o Nginx com o Let’s Encrypt é uma boa fonte.
Em seguida, adicione o seguinte trecho de código abaixo do serviço webserver. Lembre-se de definir seu nome de domínio e endereço de e-mail corretos:
|
1 2 3 4 5 6 7 8 9 10 |
#serviço certbot certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com |
A imagem certbot só será iniciada após o webserver ter iniciado, por causa da diretiva depends_on. O Docker Compose irá baixar a imagem do Certbot do Docker Hub conforme definido.
Sob a definição de volumes, o contêiner Certbot compartilhará os certificados de domínio e a chave em certbot-etc com o contêiner Nginx webserver e o código da aplicação com o contêiner app.
Sob a definição command, especificamos um subcomando para executar o comando certonly padrão do Certbot do contêiner com opções adicionais listadas abaixo:
-
--webroot: especifica o uso do plugin webroot, que coloca arquivos na pasta webroot para autenticação.--webroot-path: especifica o caminho do diretório webroot.--agree-tos: especifica que você concorda com os Termos de serviço da ACME.--no-eff-email: especifica que você não deseja compartilhar seu e-mail com a EFF. Você pode omitir isso se quiser compartilhar.--staging: diz ao Certbot que você deseja primeiro obter certificados de teste do ambiente de staging do Let’s Encrypt para testar sua configuração antes de obter o certificado real. O Let’s Encrypt possui limite de taxa de solicitação de domínio. Portanto, testar sua configuração primeiro ajudará a evitar que seu domínio seja limitado.-d: esta opção recebe os nomes de domínio para a solicitação de certificado. Neste tutorial, incluímosexample.comewww.example.com. Por favor, especifique seu domínio registrado real.
Nosso arquivo docker-compose.yml está quase completo. No entanto, você também deve adicionar as definições de rede e volume abaixo do serviço Certbot:
|
1 2 3 4 5 6 7 8 9 10 |
#Volumes volumes: certbot-etc: app: dbdata: #Redes networks: app-network: driver: bridge |
A chave volumes define os volumes a serem compartilhados com todos os serviços (contêineres) definidos neste arquivo compose: certbot-etc, app, e dbdata. Os conteúdos dos volumes que o Docker cria são armazenados em um diretório gerenciado pelo Docker no sistema de arquivos hospedeiro: /var/lib/docker/volumes/. Os conteúdos de cada volume são então montados em qualquer container que use o volume. Isso torna possível compartilhar dados e código entre containers.
A chave networks define a rede bridge que permite a comunicação entre containers. Containers na mesma rede bridge, como webserver e db podem se comunicar de forma segura através de portas sem expor o tráfego para a rede externa. Nós apenas expomos a porta 80 para permitir o acesso às páginas do site front-end.
O arquivo docker-compose.yml completo ficará assim:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
version: '3' services: #Serviço MySQL db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network #Serviço de código da aplicação WordPress app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network #Serviço Webserver Nginx webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #Serviço certbot certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com #Volumes volumes: certbot-etc: app: dbdata: #Redes networks: app-network: driver: bridge |
Você pode salvar e fechar o arquivo. No próximo passo, iniciaremos e testaremos o container e as solicitações de certificado.
Passo 4: Executando os Containers e Obtendo Certificados SSL
A maior vantagem do Docker Compose é que, uma vez definidos todos os seus serviços no docker-compose.yml arquivo, você pode iniciar todos os contêineres com apenas um comando: docker-compose up. O comando executa todas as instruções especificadas. Se as solicitações de domínio forem bem-sucedidas, você deverá ver o status de saída correto no seu terminal. Insira o seguinte comando para criar os contêineres. O -d sinalizador serve para executar os contêineres em segundo plano:
|
1 |
docker-compose up -d |
Se você vir a saída como na captura de tela abaixo, os serviços foram criados com sucesso:
Para confirmar o status dos serviços, execute o comando docker-compose ps:
|
1 |
docker-compose ps |
A saída do comando será como mostrado abaixo se tudo tiver ocorrido com sucesso. O estado dos contêineres app, db, e webserver deve ser up, e o contêiner certbot deve ter o status Exit0:
Se você vir qualquer outra coisa além de Up na coluna de estado para app, db ou webserver, ou um status Exit que não seja 0 para o contêiner certbot, então algo deu errado. Você pode verificar os logs de cada contêiner usando o comando docker-compose logs, e especificar o service_name:
|
1 |
docker-compose logs service_name |
Por exemplo, você pode verificar os logs do contêiner certbot inserindo o seguinte comando:
|
1 |
docker-compose logs certbot |
Para verificar se os certificados foram montados no contêiner webserver, use o comando docker-compose exec:
|
1 |
docker-compose exec webserver ls -la /etc/letsencrypt/live |
Se você usou um nome de domínio registrado real diferente de example.com e as solicitações de certificado foram bem-sucedidas, você deverá ver uma saída semelhante a esta:
Depois de confirmar que a solicitação de certificado foi bem-sucedida, você pode editar o arquivo docker-compose.yml e remover o sinalizador --staging. Abra o arquivo com nano:
|
1 |
nano docker-compose.yml |
Role para baixo até a seção de definição do serviço Certbot, na opção command, e substitua o sinalizador --staging pelo sinalizador --force-renewal. Isso informa ao Certbot que você está solicitando a renovação de um certificado para o mesmo domínio. A definição do seu serviço Certbot agora deve se parecer com isto:
|
1 2 3 4 5 6 7 8 9 10 |
#certbot service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com |
Salve o arquivo quando terminar de editar.
Insira o seguinte comando para recriar o contêiner certbot. O sinalizador --no-deps incluído informa ao Compose para ignorar a reinicialização do serviço do servidor web, pois ele já está em execução:
|
1 |
docker-compose up --force-recreate --no-deps Certbot |
O comando exibe a seguinte captura de tela, mostrando que a solicitação de certificado foi bem-sucedida:
Isso é tudo para esta etapa. Na próxima etapa, você modificará o arquivo de configuração do Nginx para incluir o certificado SSL.
Etapa 5: Habilitando SSL na Configuração do Nginx e na Definição do Serviço
Para fazer com que o Nginx sirva tráfego por SSL seguro, primeiro você modificará o arquivo de configuração do Nginx para adicionar um redirecionamento de HTTP para HTTPS. Em seguida, você precisa especificar os locais do certificado e da chave e, finalmente, adicionar parâmetros de segurança e cabeçalhos.
Antes de modificar o arquivo de configuração, você deve obter os parâmetros de segurança recomendados do Nginx do repositório GitHub do Certbot usando o curl com o seguinte comando:
|
1 |
curl -sSLo nginx-conf/options-ssl-nginx.conf |
O comando é executado e salva os parâmetros extraídos em um arquivo chamado options-ssl-nginx.conf, dentro do diretório nginx-conf. Remova o arquivo de configuração do Nginx para que possamos criar um novo com os seguintes comandos:
|
1 2 |
rm nginx-conf/nginx.conf nano nginx-conf/nginx.conf |
No arquivo agora vazio nginx.conf, adicione o seguinte código que inclui um redirecionamento de HTTP para HTTPS, protocolos de credenciais SSL e cabeçalhos de segurança. Como você fez anteriormente, substitua o domínio example.com pelo seu próprio domínio registrado:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
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; index index.php index.html index.htm; root /var/www/html; server_tokens off; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; include /etc/nginx/conf.d/options-ssl-nginx.conf; 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-Segurança-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # habilite o strict transport security apenas se você entender as implicações location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app: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; } } |
No primeiro bloco de servidor que lida com requisições não seguras usando a porta 80, especificamos a raiz da web (webroot) para requisições de renovação do Certbot. Também incluímos uma diretiva de redirecionamento que redireciona requisições HTTP para HTTPS.
O segundo bloco de servidor lida com tráfego seguro HTTPS vindo na porta 443. Como você pode ver, também habilitamos SSL e HTTP2. O HTTP/2 melhora o desempenho do seu servidor. Você pode ler mais sobre isso na documentação oficial do Nginx sobre HTTP/2.
Neste bloco, também especificamos que o Nginx inclua os locais do certificado SSL e da chave, bem como os parâmetros de segurança recomendados do Certbot que o curl salvou no diretório nginx-conf/options-ssl-nginx.conf.
Os cabeçalhos de segurança adicionais servem para melhorar as avaliações do seu site em sites de teste de segurança como Security Headers e SSL Labs. Você pode seguir os links nesses cabeçalhos para saber mais: X-Frame-Options, Referrer Policy, X-Content-Type-Options, X-XSS-Protection, Content-Security-Policy. Nós comentamos o cabeçalho HTTP Strict Transport Security (HSTS). Você é livre para ler sobre sua funcionalidade de preload e decidir se deseja habilitá-la.
O restante das diretivas, como root, index, e blocos de localização específicos do WordPress permanecem como discutido no Passo 1. Agora você pode salvar e fechar o arquivo quando terminar de editar.
Agora que habilitamos o tráfego HTTPS que usa a porta 443,, também devemos habilitar a porta na definição de serviço do servidor web. Insira o seguinte comando para abrir o arquivo docker-compose.yml com o nano:
|
1 |
nano docker-compose.yml |
Na seção do servidor web sob a opção ports, adicione um mapeamento para a porta 443 como destacado abaixo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
O arquivo docker-compose.yml completo deve agora se parecer com isto:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
version: '3' services: #Serviço MySQL db: image: mysql:8.0 container_name: db restart: unless-stopped env_file: .env environment: - MYSQL_DATABASE=wordpress volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network #Serviço de código da aplicação WordPress app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app restart: unless-stopped env_file: .env environment: - WORDPRESS_DB_HOST=db:3306 - WORDPRESS_DB_USER=$MYSQL_USER - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD - WORDPRESS_DB_NAME=wordpress volumes: - app:/var/www/html networks: - app-network #Serviço de servidor web Nginx webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #Serviço certbot certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com #Volumes volumes: certbot-etc: app: dbdata: #Redes networks: app-network: driver: bridge |
Depois de confirmar que tudo parece correto, salve e feche o arquivo. Depois disso, execute o seguinte comando para recriar o webserver serviço:
|
1 |
docker-compose up -d --force-recreate --no-deps webserver |
|
1 |
docker-compose ps |
Agora que todos os seus contêineres estão em execução, é possível prosseguir com a configuração do WordPress a partir da interface web.
Passo 6: Conclua a Configuração do Seu WordPress a partir da Interface Web
Navegue até o nome de domínio do seu servidor para continuar a instalação. Você deverá ver a página inicial de configuração do WordPress. Ela lhe dá as boas-vindas para escolher seu idioma antes de continuar:
Escolha seu idioma e clique em Continuar para avançar para a próxima página:
Nesta página, preencha o título do seu site, escolha um nome de usuário memorável e uma senha forte. Recomenda-se não usar Admin como seu nome de usuário por motivos de segurança. Insira seu e-mail e clique no botão Instalar WordPress para começar a instalar o WordPress.
Assim que a instalação for concluída, você será levado para a tela de login, onde fornecerá o nome de usuário e a senha que definiu. Ao inserir as credenciais válidas, você deverá conseguir ver o painel do seu WordPress:
Você instalou o WordPress com sucesso! Em seguida, você precisa seguir as etapas para garantir que os certificados SSL sejam renovados automaticamente.
Etapa 7: Configurando a Renovação Automática do Certificado SSL
Os certificados TLS/SSL da Let’s Encrypt são válidos por apenas 90 dias. Cabe a você criar uma configuração de renovação automática para garantir que eles não expirem. Você pode fazer isso criando um script e agendando-o com o utilitário cron job. Nesta etapa, mostraremos como criar um script que renovará os certificados. Em seguida, iremos agendá-lo com o utilitário cron job para executá-lo periodicamente e renovar os certificados se eles estiverem próximos da data de expiração.
Dentro do diretório do projeto wordpress_docker, abra um script chamado ssl_renewer.sh com o nano:
|
1 |
nano ssl_renewer.sh |
Adicione o seguinte código ao script para lidar com a renovação automática e o recarregamento da configuração do Nginx. Lembre-se de substituir o nome de usuário destacado pelo seu nome de usuário não-root:
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose –ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
Neste script, atribuímos o binário docker-compose a uma variável chamada COMPOSE. Também incluímos a opção –ansi never que diz ao script para executar comandos docker-compose sem caracteres de controle ANSI. Além disso, atribuímos o binário do Docker a uma variável chamada DOCKER.
O script então entra no diretório do nosso projeto wordpress_docker e executa os seguintes comandos:
docker-compose run: inicia o contêiner certbot e substitui o comando que fornecemos na definição do serviço certbot. Em vez de executar o subcomando certonly, ele executa o subcomando renew, que renovará os certificados SSL/TLS do Let’s Encrypt se estiverem prestes a expirar.docker-compose kill: envia um sinal SIGHUP ao contêinerwebserverpara recarregar as configurações do Nginx. Você pode querer dar uma olhada neste tutorial do Docker sobre como usar a imagem oficial do Nginx no Docker.docker system prune: este comando remove todos os contêineres e imagens não utilizados.
Salve e feche o arquivo quando terminar de editar. Em seguida, execute o seguinte comando para torná-lo executável:
|
1 |
chmod +x ssl_renewer.sh |
Depois de torná-lo executável, abra o seu arquivo crontab root para executar o script periodicamente nos intervalos que iremos especificar:
|
1 |
sudo crontab -e |
O crontab solicitará que você escolha seu editor preferido se for a primeira vez que o utiliza:
Escolha seu editor preferido e pressione Enter para abrir o arquivo. No final do arquivo, adicione a seguinte linha:
|
1 |
*/5 * * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
Isso define o intervalo para cinco minutos para nos permitir testar se o nosso script de renovação funcionará ou não. Também especificamos um arquivo de log que conterá a saída do trabalho: cron_docker.log.
Aguarde cinco minutos e verifique o cron.log para ver se o script teve sucesso com a solicitação de renovação:
|
1 |
tail -f /var/log/cron_docker.log |
Você deve ver algo semelhante à captura de tela abaixo se as solicitações forem bem-sucedidas:
Agora que testamos e confirmamos que está funcionando, você pode modificar o crontab para especificar uma renovação diária. Por exemplo, você pode querer especificar que o script seja executado todos os dias às 18h. Para fazer isso, modifique a última linha do crontab para que fique assim:
|
1 |
0 18 * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
Além disso, você precisa remover o –dry-run flag do ssl_renewer.sh script para garantir que a renovação real ocorra quando ele for executado. Ele deve ficar assim:
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
Em seguida, salve e feche o arquivo. Feito isso, a tarefa cron manterá seus scripts válidos, renovando-os antes do fim dos 90 dias.
Conclusão
Se você chegou até aqui no tutorial, pode se considerar um passo mais perto de se tornar um Engenheiro DevOps. Você foi capaz de criar um script de configuração do Nginx, criou um docker-compose.yml e definiu vários serviços necessários para executar uma aplicação WordPress com Docker e Docker Compose. Você obteve certificados SSL/TLS do Let’s Encrypt para garantir que seu servidor web esteja seguro. Finalmente, você criou uma tarefa cron para garantir que os certificados não expirem. Bom trabalho!
Se você está tentando se aprofundar em DevOps, dê uma olhada em mais recursos sobre containers no nosso blog:
- Conhecendo o Kubernetes
- Como implantar um aplicativo Node.js (Express.js) com Docker no Ubuntu 20.04
- Implantar uma aplicação PHP em um cluster Kubernetes com Ubuntu 18.04.
- Implantando Laravel, Nginx e MySQL com Docker Compose
Feliz Computação!










Comentários
Nenhum comentário ainda. Seja o primeiro.