Conteúdo
Tutorial de WordPress com Docker Compose: configure WordPress e MySQL
Nesta seção, você vai configurar um site WordPress completo com Docker Compose. Ao terminar, terá:
- WordPress (PHP + Apache, imagem oficial
wordpress:7-apache) - Banco de dados MySQL 8.4 com verificação de integridade; o WordPress só inicia quando o banco estiver pronto
- Dados armazenados em um Volume, preservados mesmo se você excluir e recriar os contêineres
- Limite de tamanho dos arquivos enviados ajustado para 64 MB
- Interface de administração do phpMyAdmin, iniciada somente quando necessário
A sintaxe do Compose usada nesta seção (depends_on, healthcheck, profiles, .env) já foi apresentada em Introdução ao Compose e comandos docker compose.
Crie o projeto
Crie a pasta wordpress e coloque nela estes três arquivos:
wordpress/
├── compose.yaml
├── .env
└── uploads.ini
.env: senhas
MYSQL_ROOT_PASSWORD=change-this-root-password
MYSQL_PASSWORD=change-this-wp-password
Substitua os valores pelas suas próprias senhas. O Compose lê automaticamente o arquivo .env na mesma pasta e substitui variáveis como ${MYSQL_PASSWORD} em compose.yaml pelos valores definidos nele. Não envie .env para o Git.
uploads.ini: tamanho dos uploads
O limite padrão de upload do PHP na imagem WordPress é de apenas 2 MB. O envio de imagens ou temas um pouco maiores falhará. Substitua essa configuração com um arquivo ini:
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
A imagem oficial do PHP lê todos os arquivos .ini em /usr/local/etc/php/conf.d/, então basta montar este arquivo nesse diretório.
compose.yaml
services:
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
restart: unless-stopped
wordpress:
image: wordpress:7-apache
depends_on:
db:
condition: service_healthy
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- wp_data:/var/www/html
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
restart: unless-stopped
phpmyadmin:
image: phpmyadmin
depends_on:
- db
ports:
- "127.0.0.1:8081:80"
environment:
PMA_HOST: db
profiles: [tools]
volumes:
db_data:
wp_data:
Veja o que cada configuração faz:
| Configuração | Função |
|---|---|
MYSQL_DATABASE / MYSQL_USER / MYSQL_PASSWORD | Na primeira inicialização da imagem MySQL (quando a pasta está vazia), cria automaticamente o banco de dados e a conta |
healthcheck | A cada 10 segundos, usa mysqladmin ping para verificar se é possível se conectar ao MySQL. Use -h 127.0.0.1 em vez de localhost; caso contrário, o serviço pode ser considerado healthy antes de a inicialização terminar. Veja o motivo em MySQL |
condition: service_healthy | Inicia o WordPress somente quando db estiver healthy, evitando que o WordPress suba antes e não consiga se conectar ao banco de dados |
WORDPRESS_DB_HOST: db | Conecta-se usando o nome do serviço db; a rede do Compose o resolve automaticamente para o IP do contêiner MySQL |
db_data:/var/lib/mysql | Os dados do MySQL ficam no Volume |
wp_data:/var/www/html | Os arquivos do WordPress, plugins, temas e mídias enviadas ficam no Volume |
profiles: [tools] | O phpMyAdmin não inicia por padrão. Ele só inicia quando você adiciona --profile tools |
127.0.0.1:8081:80 | O phpMyAdmin fica vinculado apenas ao host local, sem acesso externo |
O WordPress acessa o MySQL somente pela rede interna do Compose. Por isso, db não tem a configuração ports e não fica exposto externamente.
Iniciar
Execute na pasta wordpress:
$ docker compose up -d
[+] up 32/32
✔ Image wordpress:7-apache Pulled 28.0s
✔ Network wordpress_default Created 0.1s
✔ Volume wordpress_db_data Created 0.0s
✔ Volume wordpress_wp_data Created 0.0s
✔ Container wordpress-db-1 Healthy 11.1s
✔ Container wordpress-wordpress-1 Started 11.3s
Observe a ordem: o Compose cria primeiro a rede e os dois volumes. Depois que wordpress-db-1 espera 11 segundos e fica Healthy, wordpress-wordpress-1 é iniciado. Esse é o efeito de condition: service_healthy. Na primeira execução, é preciso baixar as imagens, então o processo demora um pouco mais.
Confira o status:
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
wordpress-db-1 mysql:8.4 "docker-entrypoint.s…" db 16 seconds ago Up 16 seconds (healthy) 3306/tcp, 33060/tcp
wordpress-wordpress-1 wordpress:7-apache "docker-entrypoint.s…" wordpress 16 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp
O STATUS de db mostra (healthy), e PORTS mostra apenas a porta interna do contêiner, 3306/tcp, sem mapeamento para o host. Já wordpress mapeia a porta 8080 do host para a porta 80 do contêiner.
Os dois volumes também foram criados. Seus nomes seguem o formato "nome_do_projeto_nome_do_volume", e, por padrão, o nome do projeto é o nome da pasta:
$ docker volume ls
DRIVER VOLUME NAME
local wordpress_db_data
local wordpress_wp_data
Concluir a instalação no navegador
Acesse http://localhost:8080. A primeira tela permite escolher o idioma. Na lista, selecione o idioma desejado para o painel (por exemplo, "Português do Brasil") e clique em Continue. As capturas de tela deste tutorial usam English (United States) para serem compartilhadas com as versões em outros idiomas.
Em seguida, preencha as informações do site:

| Campo | Descrição |
|---|---|
| Site Title | Título do site, que pode ser alterado depois no painel |
| Username | Nome de usuário do administrador. Não use admin, pois é fácil de adivinhar (este exemplo serve apenas para demonstração) |
| Password | Senha do administrador; o WordPress mostra o nível de segurança |
| Your Email | E-mail do administrador, usado para receber notificações e redefinir a senha |
| Search engine visibility | Se você marcar esta opção, será solicitado aos mecanismos de busca que não indexem o site. Marque-a enquanto o site estiver em teste |
A tela de configuração do banco de dados não aparece aqui, porque as variáveis de ambiente WORDPRESS_DB_* já fornecem as informações de conexão. A imagem criou automaticamente o arquivo wp-config.php ao iniciar.
Depois de clicar em Install WordPress, a tela Success indica que a instalação foi concluída:


http://localhost:8080/wp-login.phpEntre com o nome de usuário e a senha que acabou de definir para acessar o painel de administração. O bloco de boas-vindas mostra a versão 7.1.3, incluída na imagem wordpress:7-apache no momento da criação:

Na página pública, em http://localhost:8080, você já pode ver o artigo padrão Hello world!:

Conferir o limite de tamanho dos uploads
No painel, acesse Media → Add Media File. Abaixo da área de upload, aparece o limite atual. A indicação Maximum upload file size: 64 MB mostra que uploads.ini está funcionando:

Se o limite continuar em 2 MB, confira se o caminho de montagem de uploads.ini está correto. Depois de alterá-lo, recrie o contêiner com docker compose up -d (restart não aplica a nova configuração).
Como gerenciar o banco de dados com phpMyAdmin (opcional)
O phpMyAdmin está configurado com profiles: [tools], então ele não é iniciado pelo comando habitual docker compose up -d. Quando precisar, adicione --profile tools:
$ docker compose --profile tools up -d phpmyadmin
[+] up 25/25
✔ Image phpmyadmin Pulled 6.3s
✔ Container wordpress-db-1 Running 0.0s
✔ Container wordpress-phpmyadmin-1 Started 0.6s
O comando especifica phpmyadmin no final, então inicia apenas esse serviço (e sua dependência, db, que já está em execução).
Acesse http://localhost:8081, preencha Username com root e Password com o valor de MYSQL_ROOT_PASSWORD em .env:

Depois de entrar, clique no banco de dados wordpress à esquerda para ver as 12 tabelas criadas pelo WordPress (wp_posts, wp_options, wp_users…):

A porta do phpMyAdmin está vinculada a 127.0.0.1, então só pode ser acessada localmente. Se o servidor for remoto, conecte-se por um túnel SSH (ssh -L 8081:127.0.0.1:8081 usuário@servidor); não o exponha à internet. Quando terminar, você pode parar apenas esse serviço:
docker compose --profile tools stop phpmyadmin
Onde os dados ficam
| Volume | Conteúdo |
|---|---|
wordpress_db_data | Banco de dados MySQL: posts, páginas, configurações, usuários e comentários |
wordpress_wp_data | Arquivos do WordPress, temas, plugins e mídia enviada (wp-content/uploads) |
Você precisa fazer backup dos dois para conseguir restaurar o site por completo.
Backup
Execute os comandos na pasta do projeto. Primeiro, use mysqldump para exportar o banco de dados. Depois, empacote o Volume wp_data em um arquivo tar.gz com um contêiner alpine temporário:
$ docker compose exec -T db sh -c 'mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" wordpress' > wordpress.sql
mysqldump: [Warning] Using a password on the command line interface can be insecure.
$ ls -lh wordpress.sql && head -n 5 wordpress.sql
-rw-r--r-- 1 root root 880.8K Oct 13 00:22 wordpress.sql
-- MySQL dump 10.13 Distrib 8.4.11, for Linux (x86_64)
--
-- Host: localhost Database: wordpress
-- ------------------------------------------------------
-- Server version 8.4.11
$ docker run --rm -v "$(basename "$PWD")_wp_data:/data:ro" -v "$PWD:/backup" alpine:3.23 tar czf /backup/wp_data.tar.gz -C /data .
$ ls -lh wp_data.tar.gz
-rw-r--r-- 1 root root 33.9M Oct 13 00:22 wp_data.tar.gz
Explicação:
exec -T: desativa o TTY para que a saída possa ser redirecionada corretamente para um arquivo com>.sh -c '... -p"$MYSQL_ROOT_PASSWORD"': use aspas simples para expandir a variável dentro do contêiner (o contêiner MySQL tem essa variável de ambiente). Assim, o host não precisa conhecer a senha.[Warning] Using a password on the command line interface can be insecure.é um aviso do MySQL enviado para stderr; ele não é incluído emwordpress.sqle pode ser ignorado.- O início de
wordpress.sqlcontémMySQL dump … Distrib 8.4.11, o que indica que a exportação foi concluída com sucesso. $(basename "$PWD")_wp_datamonta o nome do Volumewordpress_wp_data. Se o nome da pasta for diferente, confirme comdocker volume ls.:roindica uma montagem somente leitura; o processo de backup não altera os dados.
Copie wordpress.sql e wp_data.tar.gz para outra máquina ou para um armazenamento na nuvem para ter um backup de verdade.
Backup no Windows
O PowerShell não oferece suporte a <, e o > do Windows PowerShell 5.1 salva arquivos SQL em UTF-16. Gere o arquivo no contêiner e copie-o com docker compose cp. Para empacotar wp_data, informe diretamente o nome do Volume (por padrão, nome_da_pasta_wp_data):
docker compose exec db sh -c 'mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --result-file=/tmp/wordpress.sql wordpress'
docker compose cp db:/tmp/wordpress.sql wordpress.sql
docker run --rm -v wordpress_wp_data:/data:ro -v "$(pwd):/backup" alpine:3.23 tar czf /backup/wp_data.tar.gz -C /data .
docker compose exec db sh -c 'mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --result-file=/tmp/wordpress.sql wordpress'
docker compose cp db:/tmp/wordpress.sql wordpress.sql
docker run --rm -v wordpress_wp_data:/data:ro -v "${PWD}:/backup" alpine:3.23 tar czf /backup/wp_data.tar.gz -C /data .
docker compose exec db sh -c "mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --result-file=/tmp/wordpress.sql wordpress"
docker compose cp db:/tmp/wordpress.sql wordpress.sql
docker run --rm -v wordpress_wp_data:/data:ro -v "%cd%:/backup" alpine:3.23 tar czf /backup/wp_data.tar.gz -C /data .
Para restaurar, faça o caminho inverso: docker compose cp wordpress.sql db:/tmp/restore.sql e depois docker compose exec db sh -c 'mysql -uroot -p$MYSQL_ROOT_PASSWORD wordpress < /tmp/restore.sql'. O empacotamento e a extração do tar acontecem dentro do contêiner alpine, sem serem afetados pelo Windows.
Restauração
Na máquina nova (ou depois de limpar a atual), coloque compose.yaml, .env, uploads.ini e os dois arquivos de backup no lugar. Em seguida:
# 1. Inicie somente o banco de dados e aguarde ele ficar healthy
docker compose up -d --wait db
# 2. Importe o banco de dados
docker compose exec -T db sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wordpress' < wordpress.sql
# 3. Restaure os arquivos do WordPress no Volume
docker run --rm \
-v "$(basename "$PWD")_wp_data:/data" \
-v "$PWD:/backup" \
alpine:3.23 sh -c "cd /data && tar xzf /backup/wp_data.tar.gz"
# 4. Inicie todos os serviços
docker compose up -d
--wait aguarda o serviço ficar healthy antes de retornar, evitando que a importação comece antes de o banco de dados estar pronto. A senha em .env deve ser igual à usada no backup, pois wp-config.php (em wp_data) guarda a senha antiga do banco de dados.
Atualização
Você pode atualizar o núcleo do WordPress, os temas e os plugins diretamente no painel administrativo. Os arquivos serão gravados no volume wp_data.
Para atualizar as próprias imagens (versões menores do PHP, Apache e MySQL):
$ docker compose pull
[+] pull 2/2
✔ Image wordpress:7-apache Pulled 0.6s
✔ Image mysql:8.4 Pulled 0.7s
$ docker compose up -d
[+] up 2/2
✔ Container wordpress-wordpress-1 Running 0.0s
✔ Container wordpress-db-1 Healthy 0.5s
pull baixa as imagens mais recentes; up -d recria apenas os contêineres cujas imagens mudaram. No exemplo acima, não há novas versões das imagens, então os contêineres permanecem em Running.
Observações:
- Faça um backup antes de atualizar.
wordpress:7-apacheacompanha as atualizações da versão 7.x; para fixar uma versão, você pode especificar o número completo, por exemplo,wordpress:7.1.3-apache.- Quando já há arquivos do WordPress em
wp_data, a imagem não os sobrescreve. Portanto, atualize a versão do núcleo do WordPress pelo painel administrativo. - Antes de atualizar o MySQL entre versões principais (por exemplo, 8.0 → 8.4), leia as instruções oficiais de atualização do MySQL. Não altere a tag diretamente.
Excluir todo o ambiente
Para limpar tudo depois de praticar, adicione --profile tools para também excluir o phpMyAdmin; -v exclui os volumes, e todos os dados do site serão perdidos:
$ docker compose --profile tools down -v
[+] down 6/6
✔ Container wordpress-wordpress-1 Removed 1.5s
✔ Container wordpress-phpmyadmin-1 Removed 1.5s
✔ Container wordpress-db-1 Removed 2.3s
✔ Volume wordpress_wp_data Removed 0.3s
✔ Network wordpress_default Removed 0.2s
✔ Volume wordpress_db_data Removed 0.3s
Considerações para colocar em produção
- Coloque um proxy reverso na frente para lidar com HTTPS, como Nginx, Caddy ou Traefik. Consulte Site estático e proxy reverso com Nginx.
- Não exponha o banco de dados externamente com
portse não deixe o phpMyAdmin acessível pela internet. - Não use
admincomo nome da conta de administrador e escolha uma senha forte. - Faça backups automáticos regularmente (por exemplo, usando cron para executar o comando de backup acima) e armazene-os em outra máquina.
- Não envie
.envpara o Git.
Resumo
- Gerencie o WordPress e o MySQL com Compose. Os dados ficam nos volumes
db_dataewp_data, respectivamente. - Na verificação de integridade do MySQL, use
-h 127.0.0.1para evitar que ele seja considerado saudável durante a inicialização. - Coloque o phpMyAdmin em um profile e vincule-o apenas a 127.0.0.1.
- O backup deve incluir tanto o banco de dados quanto os arquivos do site e ser armazenado em outra máquina.
Exercícios
Exercício 1: use um comando para confirmar que o limite de upload do PHP agora é 64M.
Resposta
docker compose exec wordpress php -r "echo ini_get('upload_max_filesize');"
O resultado é 64M.
Exercício 2: você precisa migrar o site para outro host. Quais arquivos deve levar?
Resposta
compose.yaml, .env, uploads.ini e os dois backups: wordpress.sql (banco de dados) e wp_data.tar.gz (arquivos do site). No novo host, siga as etapas de “Restauração” deste capítulo.
Perguntas frequentes
Por que a tela de instalação não pede as configurações do banco de dados?
As variáveis de ambiente WORDPRESS_DB_* já fornecem as informações de conexão, e a imagem gera automaticamente o wp-config.php ao iniciar.
Aparece um aviso de que o arquivo enviado excede o limite de tamanho?
O limite padrão de upload do PHP na imagem WordPress é 2 MB. Ajuste-o com uploads.ini, conforme este capítulo, e recrie o contêiner com docker compose up -d após a alteração.
Como faço backup no Windows?
O PowerShell não oferece suporte a <, e o > do Windows PowerShell 5.1 altera a codificação do arquivo. A seção “Backup” deste capítulo mostra como exportar de dentro do contêiner e depois copiar o arquivo com docker cp.
Atualizado 14 de outubro de 2026