Como instalar o WordPress com o Docker Compose

Introdução

O WordPress é um Sistema de gerenciamento de conteúdo (CMS) de código aberto e gratuito, construído em um banco de dados MySQL com o processamento de PHP. Graças a sua arquitetura de plug-in extensível, o sistema de criação de modelos e o fato de que pode ser administrado quase que totalmente através de uma interface Web, o WordPress é uma escolha popular na criação de diferentes tipos de websites, de blogs a páginas de produtos e sites de eCommerce.

Executar o WordPress normalmente envolve a instalação de uma pilha LAMP (Linux, Apache, MySQL e PHP) ou LEMP (Linux, Nginx, MySQL e PHP), o que pode demorar um pouco. No entanto, ao utilizar as ferramentas como o Docker e o Docker Compose,você simplifica o processo de configuração de sua pilha preferida assim como o processo de instalação do WordPress. Em vez de instalar componentes individuais manualmente, você pode usar images que padronizemam coisas como bibliotecas, arquivos de configuração e variáveis de ambiente e executar essas imagens em containers – processos isolados que são executados em um sistema operacional compartilhado. Além disso, usando o Compose você pode coordenar vários contêineres — por exemplo, um aplicativo e um banco de dados — para se comunicarem uns com os outros.

Neste tutorial, você construirá uma instalação do WordPress com vários contêineres. Seus contêineres incluirão um banco de dados MySQL, um servidor Web Nginx e o próprio WordPress. Você também irá proteger sua instalação, obtendo certificados TLS/SSL com o Let’s Encrypt para o domínio que quiser que seja associado ao seu site. Por fim, você irá configurar um trabalho cron para renovar seus certificados para que seu domínio permaneça seguro.

Pré-requisitos

Para seguir este tutorial, será necessário:

  • Um servidor executando o Ubuntu 18.04, junto com um usuário não raiz com privilégios sudo e um firewall ativo. Para saber como configurar isso, consulte este guia de Configuração inicial do servidor.
  • O Docker instalado no seu servidor, seguindo os Passos 1 e 2 do artigo sobre Como instalar e usar o Docker no Ubuntu 18.04.
  • O Docker Compose instalado no seu servidor, seguindo o Passo 1 do artigo sobre Como instalar o Docker Compose no Ubuntu 18.04.
  • Um nome de domínio registrado. Este tutorial usará o example.com do início ao fim. Você pode obter um domínio gratuitamente através do Freenom, ou usar o registrador de domínios de sua escolha.
  • Ambos os registros de DNS a seguir serão configurados para o seu servidor. Você pode seguir esta introdução para o DNS da DigitalOcean para obter mais detalhes sobre como adicioná-los a uma conta da DigitalOcean, caso seja o que estiver usando:

    • Um registro A com example.com apontando para o endereço de IP público do seu servidor.
    • Um registro A com www.example.com apontando para o endereço de IP público do seu servidor.

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

Antes de executar quaisquer contêineres, nosso primeiro passo será definir a configuração do nosso servidor Web Nginx. Nosso arquivo de configuração incluirá alguns blocos de localização específicos do WordPress, junto com um bloco de localização para pedidos de verificação diretos do Let’s Encrypt para o cliente Certbot para a renovação automatizada de certificados.

Primeiro, crie um diretório de projeto para sua configuração do WordPress chamada wordpress e navegue até ele:

  • mkdir wordpress && cd wordpress

Em seguida, crie um diretório para o arquivo de configuração:

  • mkdir nginx-conf

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

  • nano nginx-conf/nginx.conf

Neste arquivo, iremos adicionar um bloco de servidor com diretivas relacionadas ao nome do servidor e à raiz do documento, além de blocos de localização para direcionar os pedidos do cliente Certbot para os certificados, processamento de PHP e pedidos de ativos estáticos.

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

~/wordpress/nginx-conf/nginx.conf

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 wordpress: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: diz ao Nginx para escutar na porta 80, que nos permitirá usar o plug-in webroot do Certbot para nossos pedidos de certificados. Note que ainda não estamos incluindo a porta 443 — atualizaremos nossa configuração para incluir o SSL assim que tivermos tido sucesso na obtenção dos nossos certificados.
  • server_name: define seu nome do servidor e o bloco de servidor que devem ser usados para os pedidos feitos para o seu servidor. Certifique-se de substituir o example.com nesta linha com seu próprio nome de domínio.
  • index: a diretriz index define os arquivos que serão usados como índices durante o processamento dos pedidos para o seu servidor. Aqui, nós modificamos a ordem padrão de prioridade, passando o index.php na 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 pedidos feitos 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 WordPress. Essas instruções do Dockerfile também garantem que os arquivos da versão do WordPress estejam montados neste volume.

Blocos de localização:

  • location ~ /.well-known/acme-challenge: este bloco de localização irá lidar com pedidos para feitos 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 essa configuração feita, poderemos usar o plug-in webroot do Certbot para obter certificados para o nosso domínio.
  • location /: neste bloco de localização, usaremos uma diretriz try_files para verificar se há arquivos que correspondam os pedidos 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 WordPress com os argumentos do pedido.
  • location ~ .php$: este bloco de localização irá lidar com o processamento e o proxy do PHP desses pedidos para o nosso contêiner do wordpress. Como nossa imagem do WordPress Docker 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 exige um processador de PHP independente para os pedidos PHP: no nosso caso, esses pedidos serão tratados 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 pedidos de proxy para o aplicativo do WordPress em execução no nosso contêiner do wordpress, ajuste do índice preferido em relação aos pedidos de URI analisados e analise os pedidos de URI.
  • location ~ /.ht: este bloco irá lidar com arquivos .htaccess já que o Nginx não os atenderá. A diretriz deny_all garante que os arquivos .htaccess nunca sejam atendidos 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 dos pedidos de ativos estáticos e garante que esses ativos permaneçam altamente armazenáveis em cache, uma vez que são normalmente dispendiosos de servir.

Para obter mais informações sobre o FastCGI em proxy, 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. Se usou o nano, salve e feche o arquivo, pressionando as teclas CTRL+X, Y e, depois ENTER.

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

O seu banco de dados e os contêineres do aplicativo do WordPress precisarão de acesso a certas variáveis de ambiente no tempo de execução, para que seus dados do aplicativo persistam e estejam acessíveis para o seu aplicativo. Essas variáveis incluem tanto informações confidenciais quanto não confidenciais: valores confidenciais relacionados à senha** raiz **do seu MySQL, o usuário e senha do banco de dados do aplicativo e as informações não confidenciais do nome e do host do banco de dados do seu aplicativo

Em vez de definir todos esses valores no nosso arquivo Docker Compose — o arquivo principal que contém informações sobre como nossos contêineres irão executar — podemos definir os valores confidenciais em um 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 seu projeto, ~/wordpress, abra um arquivo chamado .env:

  • nano .env

Os valores confidenciais que vamos definir neste arquivo incluem uma senha para nosso usuário raiz do MySQL e um nome de usuário e senha que o WordPress usará para acessar o banco de dados.

Adicione os seguintes nomes de variáveis e valores ao arquivo. Lembre-se de fornecer seus próprios valores aqui em relação a cada variável:

~/wordpress/.env

MYSQL_ROOT_PASSWORD=your_root_password MYSQL_USER=your_wordpress_database_user MYSQL_PASSWORD=your_wordpress_database_password 

Nós incluímos uma senha para a conta administrativa raiz, assim como nosso nome de usuário e senha escolhidos para nosso banco de dados do aplicativo.

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

Como seu arquivo .env contém informações confidenciais, você irá querer garantir que ele seja incluído nos arquivos .gitignore e .dockerignore, os quais dizem ao Git e ao Docker quais arquivos *não *copiar para os seus repositórios Git e imagens do Docker, respectivamente.

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

Depois, abra um arquivo .gitignore:

  • nano .gitignore

Adicione o .env ao arquivo:

~/wordpress/.gitignore

.env 

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

De igual modo, como boa medida de precaução, adicione .env em um arquivo .dockerignore, para que ele não acabe nos seus contêineres quando estiver usando esse diretório como seu contexto de compilação.

Abra o arquivo:

  • nano .dockerignore

Adicione o .env ao arquivo:

~/wordpress/.dockerignore

.env 

Opcionalmente, abaixo disso você pode adicionar arquivos e diretórios associados ao desenvolvimento do seu aplicativo:

~/wordpress/.dockerignore

.env .git docker-compose.yml .dockerignore 

Salve e feche o arquivo quando você terminar.

Com suas informações confidenciais prontas, agora você já pode passar a definir seus serviços em um arquivo docker-compose.yml.

Passo 3 — Definindo serviços com o Docker Compose

Seu arquivo docker-compose.yml irá conter as definições de serviço para sua configuração. Um serviço no Compose é um contêiner em execução e as definições de serviço especificam informações sobre como cada contêiner irá executar.

Ao usar o Compose, você pode definir serviços diferentes para executar aplicativos multicontêiners, já que o Compose permite que você vincule esses serviços através de redes e volumes compartilhados. Isso será útil para nossa configuração atual, já que vamos criar contêineres diferentes para o nosso banco de dados, aplicativo do WordPress e servidor Web. Também vamos criar um contêiner para executar o cliente Certbot para obter certificados para o nosso webserver.

Para começar, abra o arquivo docker-compose.yml:

  • nano docker-compose.yml

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

~/wordpress/docker-compose.yml

version: '3'  services:   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 

A definição de serviço do db contém as seguintes opções:

  • image: diz ao Compose qual imagem puxar para criar o contêiner. Estamos anexando a imagem mysql:8.0 para evitar conflitos futuros uma vez que a imagem mysql:latest continua a ser atualizada. Para obter mais informações sobre a anexação de versão e evitar conflitos de dependência, consulte a documentação do Docker sobre As melhores práticas do Dockerfile.
  • container_name: especifica um nome para o contêiner.
  • restart: define a política de reinício do contêiner. A padrão é no, mas definimos o contêiner para reiniciar, a menos que ele seja interrompido manualmente.
  • env_file: diz ao Compose que queremos adicionar as variáveis de ambiente de um arquivo chamado .env, localizado em nosso contexto de compilação. Neste caso, o contexto de compilação é o nosso diretório atual.
  • environment: permite que você adicione outras variáveis de ambiente, além das definidas no seu arquivo .env. Vamos definir a variável como MYSQL_DATABASE igual a wordpress para fornecer um nome para o banco de dados do nosso aplicativo. Como essa informação não é confidencial, podemos incluí-la diretamente no arquivo docker-compose.yml.
  • volumes: aqui, estamos montando um volume chamado de dbdata para o diretório /var/lib/mysql no contêiner. Esse é o diretório de dados padrão para o MySQL na maioria das distribuições.
  • comando: esta opção especifica um comando para substituir as instruções de CMD padrão pela imagem. No nosso caso, adicionaremos uma opção ao comando padrão mysqldda imagem do Docker, a qual inicia o servidor MySQL no contêiner. Esta opção, --default-authentication-plugin=mysql_native_password, define a variável do sistema --default-authentication-plugin como mysql_native_password, especificando qual mecanismo de autenticação deve controlar os novos pedidos de autenticação feitos para o servidor. Como o PHP e, portanto,nossa imagem do WordPress não oferecerão suporte ao padrão de autenticação mais recente do MySQL, devemos fazer esse ajuste para autenticar o usuário do banco de dados do nosso aplicativo.
  • networks: especifica que nosso serviço de aplicativo irá juntar-se à rede app-network que vamos definir no final do arquivo.

Em seguida, abaixo de sua definição de serviço db, adicione a definição para seu serviço de aplicativo do wordpress:

~/wordpress/docker-compose.yml

...   wordpress:     depends_on:       - db     image: wordpress:5.1.1-fpm-alpine     container_name: wordpress     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:       - wordpress:/var/www/html     networks:       - app-network 

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

  • depends_on: garante que nossos contêineres irão iniciar por ordem de dependência, com o contêiner do wordpress inciando após o contêiner do db. Nosso aplicativo do WordPress conta com a existência do banco de dados de nosso aplicativo e com o usuário; assim, expressar essa ordem de dependência permitirá que nosso aplicativo seja iniciado corretamente.
  • image: para essa configuração, estamos usando a imagem do WordPress 5.1.1-fpm-alpine. Como discutido no Passo 1, usar essa imagem garante que o nosso aplicativo terá o processador php-fpm que o Nginx exige para lidar com o processamento do PHP. Esta também é uma imagem alpine, derivada do projeto Linux Alpine, que ajudará a manter a dimensão geral de nossa imagem reduzida. Para obter mais informações sobre os benefícios e os problemas de se usar imagens alpine e se isso faz sentido ou não para o seu aplicativo, consulte a discussão completa sob a seção de** Image Variants** da página de imagens do Docker Hub WordPress.
  • env_file: novamente, especificamos que queremos extrair valores do nosso arquivo .env, já que é aqui que definimos o usuário do banco de dados do nosso aplicativo e a senha.
  • environment: aqui, estamos usando os valores que definimos no nosso arquivo .env, mas estamos atribuindo-os aos nomes da variável que a imagem do WordPress espera: o WORDPRESS_DB_USER e o WORDPRESS_DB_PASSWORD. Também estamos definindo uma variável WORDPRESS_DB_HOST, que será o servidor MySQL executando no contêiner do db, que pode ser acessado na porta padrão do MySQL, 3306. Nosso WORDPRESS_DB_NAME terá o mesmo valor que especificamos na definição de serviço do MySQL para nosso MYSQL_DATABASE: wordpress.
  • volumes: estamos montando um volume chamado wordpress no ponto de montagem /var/www/html criado pela imagem do WordPress. Usar um volume nomeado dessa maneira nos permitirá compartilhar o código do nosso aplicativo com outros contêineres.
  • networks: também estamos adicionando o contêiner wordpress na rede app-network.

Em seguida, abaixo da definição do serviço de aplicativo do wordpress, adicione a seguinte definição para seu serviço do Nginx webserver:

~/wordpress/docker-compose.yml

...   webserver:     depends_on:       - wordpress     image: nginx:1.15.12-alpine     container_name: webserver     restart: unless-stopped     ports:       - "80:80"     volumes:       - wordpress:/var/www/html       - ./nginx-conf:/etc/nginx/conf.d       - certbot-etc:/etc/letsencrypt     networks:       - app-network 

Novamente, estamos nomeando nosso contêiner e tornando-o dependente do contêiner wordpress por ordem de inicialização. Também estamos usando uma imagem alpine — a imagem Nginx 1.15.12-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 uma combinação de volumes nomeados e montagens associadas:
    • wordpress:/var/www/html: irá montar o código de nosso aplicativo WordPress no diretório /var/www/html – o diretório que definimos como raiz no bloco de nosso servidor Nginx.
    • ./nginx-conf:/etc/nginx/conf.d: irá associar a montagem do diretório de configuração do Nginx no host ao diretório relevante no contêiner, garantindo que quaisquer alterações que façamos em arquivos no host serão refletidas no contêiner.
    • certbot-etc:/etc/letsencrypt: irá montar os certificados e chaves relevantes do Let’s Encrypt do nosso domínio para o diretório apropriado no contêiner.

Novamente, adicionamos esse contêiner à rede app-network.

Por fim, abaixo da definição de seu webserver, adicione sua última definição de serviço para o serviço do certbot. Certifique-se de substituir o endereço de e-mail e os nomes de domínio listados aqui por suas próprias informações:

~/wordpress/docker-compose.yml

  certbot:     depends_on:       - webserver     image: certbot/certbot     container_name: certbot     volumes:       - certbot-etc:/etc/letsencrypt       - wordpress:/var/www/html     command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com 

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 no certbot-etc e o código do aplicativo no wordpress.

Novamente, usamos o depends_on para especificar que o contêiner do certbot deve ser iniciado assim que o serviço do webserver estiver em execução.

Também incluímos uma opção de command que especifica um subcomando para executar com o comando certbot padrão do contêiner. O subcomando certonly obterá um certificado com as seguintes opções:

  • --webroot: diz ao Certbot para usar o plug-in webroot para colocar arquivos na pasta webroot para autenticação. Esse plug-in depende do método de validação HTTP-01, o qual usa um pedido de HTTP para provar que o Certbot pode acessar recursos de um servidor que responde a um dado nome de domínio.
  • --webroot-path: especifica o caminho do diretório webroot.
  • --email: seu e-mail escolhido para o registro e recuperação.
  • --agree-tos: especifica que você concorda com os termos do Acordo do Assinante do protocolo ACME.
  • --no-eff-email: diz ao Certbot que você não deseja compartilhar seu e-mail com a Electronic Frontier Foundation (EFF). Sinta-se à vontade para omitir isso se preferir.
  • --staging: diz ao Certbot que você deseja usar o ambiente de preparo do Let’s Encrypt para obter certificados de teste. Usar essa opção permite que você teste suas opções de configuração e evite possíveis limites de solicitação de domínio. Para obter mais informações sobre esses limites, consulte a documentação sobre limites de taxa do Let’s Encrypt.
  • -d: permite que você especifique os nomes de domínio que gostaria de aplicar ao seu pedido. Neste caso, incluímos o example.com e www.example.com. Certifique-se de substituí-los pelo seu domínio.

Abaixo da definição do serviço do certbot, adicione sua rede e definições de volume:

~/wordpress/docker-compose.yml

... volumes:   certbot-etc:   wordpress:   dbdata:  networks:   app-network:     driver: bridge   

Nossa chave de volumes de nível superior define os volumes certbot-etc, wordpress e dbdata. 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ódigos e dados entre os contêineres.

A rede bridge app-network definida pelo usuário posibilita a comunicação entre os nossos contêineres, uma vez que eles estão no mesmo host daemon do Docker. Isso otimiza o tráfego e a comunicação dentro do aplicativo, uma vez que abre todas as portas entre os contêineres na mesma rede bridge, sem expor nenhuma das portas ao mundo exterior. Assim, nossos contêineres db, wordpress e webserver podem se comunicar uns com os outros e precisamos apenas expor a porta 80 para o acesso de front-end ao aplicativo.

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

~/wordpress/docker-compose.yml

version: '3'  services:   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    wordpress:     depends_on:       - db     image: wordpress:5.1.1-fpm-alpine     container_name: wordpress     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:       - wordpress:/var/www/html     networks:       - app-network    webserver:     depends_on:       - wordpress     image: nginx:1.15.12-alpine     container_name: webserver     restart: unless-stopped     ports:       - "80:80"     volumes:       - wordpress:/var/www/html       - ./nginx-conf:/etc/nginx/conf.d       - certbot-etc:/etc/letsencrypt     networks:       - app-network    certbot:     depends_on:       - webserver     image: certbot/certbot     container_name: certbot     volumes:       - certbot-etc:/etc/letsencrypt       - wordpress:/var/www/html     command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com  volumes:   certbot-etc:   wordpress:   dbdata:  networks:   app-network:     driver: bridge   

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

Com suas definições de serviço instaladas, você está pronto para iniciar os contêineres e testar seus pedidos de certificado.

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 nossos pedidos de domínio forem bem sucedidos, veremos o status correto da saída no nosso resultado e os certificados corretos montados na pasta /etc/letsencrypt/live no contêiner do webserver.

Crie os contêineres com o docker-compose up e o sinalizador -d, os quais executarão os contêineres db, wordpress e webserver em segundo plano:

  • docker-compose up -d

Você verá um resultado confirmando que os serviços foram criados:

OutputCreating db ... done Creating wordpress ... done Creating webserver ... done Creating certbot   ... done 

Com o uso do docker-compose ps, verifique o status dos seus serviços:

  • docker-compose ps

Se tudo ocorreu bem, seus serviços db, wordpress e webserver devem estar Up e o contêiner certbot terá fechado com uma mensagem de status 0:

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

Se você ver qualquer outra coisa além de Up na coluna State em relação aos serviços db, wordpress ou webserver ou um status de fechamento que não seja 0 em relação ao contêiner certbot, certifique-se de verificar os registros de serviço com o comando docker-compose logs:

  • docker-compose logs service_name

Agora, é possível verificar se seus certificados foram instalados no contêiner webserver com o docker-compose exec:

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

Se os seus pedidos de certificado tiverem sido bem-sucedidos, verá um resultado como este:

Outputtotal 16 drwx------    3 root     root          4096 May 10 15:45 . drwxr-xr-x    9 root     root          4096 May 10 15:45 .. -rw-r--r--    1 root     root           740 May 10 15:45 README drwxr-xr-x    2 root     root          4096 May 10 15:45 example.com 

Agora que você sabe que seu pedido será bem sucedido, você pode editar a definição do serviço certbot para remover o sinalizador --staging.

Abra o docker-compose.yml:

  • nano docker-compose.yml

Encontre a seção do arquivo com a definição de serviço do certbot e substitua o sinalizador --staging na opção command pelo sinalizador --force-renewal, o qual dirá ao Certbot que você quer solicitar um novo certificado com os mesmos domínios de um certificado existente. A definição de serviço do certbot se parecerá com isto agora:

~/wordpress/docker-compose.yml

...   certbot:     depends_on:       - webserver     image: certbot/certbot     container_name: certbot     volumes:       - certbot-etc:/etc/letsencrypt       - certbot-var:/var/lib/letsencrypt       - wordpress:/var/www/html     command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com ... 

Agora, é possível executar o docker-compose up para recriar o contêiner 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á o resultado indicando que o seu pedido de certificado foi bem-sucedido:

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 example.com certbot      | http-01 challenge for www.example.com 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/example.com/fullchain.pem certbot      |    Your key file has been saved at: certbot      |    /etc/letsencrypt/live/example.com/privkey.pem certbot      |    Your cert will expire on 2019-08-08. To obtain a new or tweaked certbot      |    version of this certificate in the future, simply run certbot certbot      |    again. To non-interactively renew *all* of your certificates, run certbot      |    "certbot renew" certbot      |  - Your account credentials have been saved in your Certbot certbot      |    configuration directory at /etc/letsencrypt. You should make a certbot      |    secure backup of this folder now. This configuration directory will certbot      |    also contain certificates and private keys obtained by Certbot so certbot      |    making regular backups of this folder is ideal. certbot      |  - If you like Certbot, please consider supporting our work by: certbot      | certbot      |    Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate certbot      |    Donating to EFF:                    https://eff.org/donate-le certbot      | certbot exited with code 0 

Com seus certificados instalados, você pode seguir em frente para modificar sua configuração do Nginx para incluir o SSL.

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

Habilitar o SSL em nossa configuração do Nginx envolverá a adição de um redirecionamento do HTTP para o HTTPS, especificando nosso certificado e locais-chave do SSL e adicionando 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

Antes de modificarmos o arquivo de configuração propriamente dito, primeiro iremos obter os parâmetros de segurança recomendados para o Nginx a partir do Certbot usando o curl:

  • curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/tls_configs/options-ssl-nginx.conf

Este comando salvará esses parâmetros em um arquivo chamado options-ssl-nginx.conf, localizado no diretório nginx-conf.

Em seguida, remova o arquivo de configuração do Nginx criado 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 o example.com pelo seu próprio domínio:

~/wordpress/nginx-conf/nginx.conf

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-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;         # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;         # enable strict transport security only if you understand the implications          location / {                 try_files $uri $uri/ /index.php$is_args$args;         }          location ~ .php$ {                 try_files $uri =404;                 fastcgi_split_path_info ^(.+.php)(/.+)$;                 fastcgi_pass wordpress: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 webroot dos pedidos de renovação do Certbot para o diretório .well-known/acme-challenge. Isso também inclui uma diretriz de reescrita, que direciona os pedidos do HTTP para o diretório raiz para o HTTPS.

O bloco de servidor HTTPS habilita o ssl e o http2. Para ler mais sobre como o HTTP/2 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.

Este bloco também inclui nosso certificado de SSL e locais de chave, junto com os parâmetros de segurança recomendados do Certbot que salvamos no nginx-conf/options-ssl-nginx.conf.

Além disso, incluímos alguns cabeçalhos de segurança que nos permitirão obter classificações A em coisas como os sites de teste do servidor SSL Labs e Security Headers. Estes cabeçalhos incluem o X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy e X-XSS-Protection. O cabeçalho HTTP Strict Transport Security (HSTS) é retirado do comentário – habilite esta opção somente se você entender as implicações e tiver avaliado sua funcionalidade de “precarregamento”.

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

Assim que terminar a edição, salve e feche o arquivo.

Antes de recriar o serviço webserver, será necessário adicionar um mapeamento da porta 443 para sua definição de serviço webserver.

Abra seu arquivo docker-compose.yml:

  • nano docker-compose.yml

Na definição do serviço webserver, adicione o seguinte mapeamento de porta:

~/wordpress/docker-compose.yml

...   webserver:     depends_on:       - wordpress     image: nginx:1.15.12-alpine     container_name: webserver     restart: unless-stopped     ports:       - "80:80"       - "443:443"     volumes:       - wordpress:/var/www/html       - ./nginx-conf:/etc/nginx/conf.d       - certbot-etc:/etc/letsencrypt     networks:       - app-network 

O arquivo docker-compose.yml ficará com a seguinte aparência quando estiver terminado:

~/wordpress/docker-compose.yml

version: '3'  services:   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    wordpress:     depends_on:       - db     image: wordpress:5.1.1-fpm-alpine     container_name: wordpress     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:       - wordpress:/var/www/html     networks:       - app-network    webserver:     depends_on:       - wordpress     image: nginx:1.15.12-alpine     container_name: webserver     restart: unless-stopped     ports:       - "80:80"       - "443:443"     volumes:       - wordpress:/var/www/html       - ./nginx-conf:/etc/nginx/conf.d       - certbot-etc:/etc/letsencrypt     networks:       - app-network    certbot:     depends_on:       - webserver     image: certbot/certbot     container_name: certbot     volumes:       - certbot-etc:/etc/letsencrypt       - wordpress:/var/www/html     command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com  volumes:   certbot-etc:   wordpress:   dbdata:  networks:   app-network:     driver: bridge   

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

Recrie o serviço webserver:

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

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

  • docker-compose ps

Você deve ver um resultado indicando que seus serviços db, wordpress e webserver estão em execução:

Output  Name                 Command               State                     Ports                   ---------------------------------------------------------------------------------------------- certbot     certbot certonly --webroot ...   Exit 0                                            db          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 wordpress   docker-entrypoint.sh php-fpm     Up       9000/tcp     

Com seus contêineres em execução, termine sua instalação do WordPress através da interface Web.

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

Com nossos contêineres em execução, podemos concluir a instalação através da interface Web do WordPress.

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

https://example.com 

Selecione o idioma que deseja usar:

Seletor de Idiomas do WordPress

Após clicar em Continuar, você irá parar na página de configuração principal, na qual você terá que escolher um nome para o seu site e um nome de usuário. Neste ponto, é uma boa ideia escolher um nome de usuário fácil de lembrar (em vez de “admin”) e uma senha forte. Você pode usar a senha que o WordPress gera automaticamente ou criar a sua própria.

Por fim, será necessário digitar seu endereço de e-mail e decidir se quer ou não evitar que os motores de busca de fazer a indexação do seu site:

Página Principal de Configuração do WordPress

Clicar em Install WordPress no final da página levará você para um prompt de login:

Tela de Log-in do WordPress

Uma vez logado, você terá acesso ao painel de administração do WordPress:

Painel Principal de Administração do WordPress

Com sua instalação do WordPress concluída, tome medidas para garantir que seus certificados SSL serão renovados 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 trabalho 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.

Primeiro, abra um script chamado ssl_renew.sh:

  • nano ssl_renew.sh

Adicione o seguinte código ao script para renovar seus certificados e recarregar a configuração do seu servidor Web. Lembre-se de substituir o nome de usuário deste exemplo pelo nome do seu usuário não raiz:

~/wordpress/ssl_renew.sh

#!/bin/bash  COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker"  cd /home/sammy/wordpress/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af 

Primeiro, este script atribui o binário docker-compose a uma variável chamada COMPOSE e especifica a opção --no-ansi, a qual executará os comandos do docker-compose sem os caracteres de controle do ANSI. Em seguida, ele faz o mesmo com o binário docker. Então, ele muda para o diretório do projeto ~/wordpress e executa os seguintes comandos docker-compose:

  • docker-compose run: iniciará um contêiner certbot e substituirá o comando fornecido em nossa definição de serviço certbot. Em vez de usar o subcomando certonly vamos usar o subcomando renew aqui, o qual renovará os certificados que estão próximos de expirar. Incluímos a opção --dry-run aqui para testar nosso script.
  • docker-compose kill: enviará um sinal SIGHUP para o contêiner webserver recarregar a configuração do Nginx. Para obter mais informações sobre o uso deste processo para recarregar sua configuração do Nginx, consulte este post do blog do Docker sobre a implantação da imagem oficial do Nginx com o Docker.

Na sequência, ele executa o docker system prune para remover todos os contêineres e imagens não utilizados.

Feche o arquivo quando terminar a edição. Torne-o executável:

  • chmod +x ssl_renew.sh

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

  • sudo crontab -e

Se esta for a primeira vez que você edita esse arquivo, será solicitado que escolha um editor:

Outputno crontab for root - using an empty one  Select an editor.  To change later, run 'select-editor'.   1. /bin/nano        <---- easiest   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:

crontab

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

Isso definirá intervalos de trabalho de cinco minutos cada, para que você possa testar se o seu pedido de renovação funcionou como o previsto. Também criamos um arquivo de registro, cron.log, para gravar o resultado relevante do trabalho.

Após cinco minutos, verifique o cron.log para ver se o pedido de renovação foi bem-sucedido:

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

Um resultado confirmando uma renovação bem-sucedida deve aparecer:

Output- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** DRY RUN: simulating 'certbot renew' close to cert expiry **          (The test certificates below have not been saved.)  Congratulations, all renewals succeeded. The following certs have been renewed:   /etc/letsencrypt/live/example.com/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry **          (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Agora, é possível modificar o arquivo crontab para definir um intervalo diário. Para executar o script todos os dias ao meio-dia, por exemplo, você modificaria a última linha do arquivo para que fique com a seguinte aparência:

crontab

... 0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1 

Você também vai querer remover a opção --dry-run do seu script ssl_renew.sh:

~/wordpress/ssl_renew.sh

#!/bin/bash  COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker"  cd /home/sammy/wordpress/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af 

Seu trabalho cron irá garantir que seus certificados do Let’s Encrypt não expirem, renovando-os quando forem elegíveis para tanto. Você também pode configurar um rodízio de registros com o utilitário Logrotate para rodiziar e comprimir seus arquivos de registro.

Conclusão

Neste tutorial, você usou o Docker Compose para criar uma instalação do WordPress com um servidor Web Nginx. Como parte deste fluxo de trabalho, você obteve certificados de TLS/SSL para o domínio que quis associado com seu site do WordPress. Além disso, criou uma tarefa cron para renovar esses certificados quando necessário.

Como passos adicionais para melhorar o desempenho e a redundância do site, consulte os seguintes artigos sobre a entrega e backup dos ativos do WordPress:

  • Como agilizar a entrega dos ativos do WordPress usando o DigitalOcean Spaces CND.
  • Como fazer backup de um site WordPress para Spaces.
  • Como armazenar ativos do WordPress no DigitalOcean Spaces.

Se estiver interessado em explorar um fluxo de trabalho em contêiner com o Kubernetes, veja:

  • Como configurar o WordPress com o MySQL no Kubernetes usando o Helm.