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.
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:
example.com
apontando para o endereço de IP público do seu servidor.www.example.com
apontando para o endereço de IP público do seu servidor.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:
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 c
omo 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.
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:
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:
.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:
.env
Opcionalmente, abaixo disso você pode adicionar arquivos e diretórios associados ao desenvolvimento do seu aplicativo:
.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
.
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
:
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 mysqld
da 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:
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
:
...
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 root
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:
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 sammy@example.com --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:
...
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:
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 sammy@example.com --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.
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:
...
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 sammy@example.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
...
Agora, é possível executar o docker-compose up
para recriar o contêiner 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.
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/_internal/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:
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:
...
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:
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 sammy@example.com --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.
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:
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:
Clicar em Install WordPress no final da página levará você para um prompt de login:
Uma vez logado, você terá acesso ao painel 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.
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:
#!/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:
...
*/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:
...
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
:
#!/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.
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:
Se estiver interessado em explorar um fluxo de trabalho em contêiner com o Kubernetes, veja:
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!
Olá, obrigado por esse material.
Minhas arquitetura é AMR64 (Ubuntu Server 20.10 + Raspberry PI4 8G)
Ao executar o comando: $ docker-compose up --force-recreate --no-deps certbot
Retorna o erro:
Recreating certbot … done Attaching to certbot certbot | standard_init_linux.go:211: exec user process caused “exec format error” certbot exited with code 1
Como proceder deste ponto para a criação dos certificado para essa arquitetura?
Muito obrigado
Hi Kathleen, i followed this article and all works properly, but for some reason, mysql container is consuming a lot of my disk space, at this time it has something around 12gb and growing up fast, i read a lot of articles and found nothing to helps me on fix it, can you help me?
Muito bom o artigo. Detalhado e com passo a passo correto. Obrigado por colocar esse conteúdo a disposição. Tenho uma pergunta. Fiz os testes pra montar e tudo funcionou muito bem. Agora, (como ainda sou bem iniciante em Docker) qual é a melhor prática pra aproveitar o que está feito e funcionando e apontar para outro domínio? Ou mesmo replicar essa VPS para alterar? Fico no aguardo. Obrigado mais uma vez. Fiquem bem.