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çãoFunção
MYSQL_DATABASE / MYSQL_USER / MYSQL_PASSWORDNa primeira inicialização da imagem MySQL (quando a pasta está vazia), cria automaticamente o banco de dados e a conta
healthcheckA 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_healthyInicia 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: dbConecta-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/mysqlOs dados do MySQL ficam no Volume
wp_data:/var/www/htmlOs 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:80O 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:

Tela de instalação do WordPress: preenchimento do título do site, nome de usuário, senha e e-mail
Tela de instalação: Site Title, Username, Password, Your Email; por fim, clique em Install WordPress
CampoDescrição
Site TitleTítulo do site, que pode ser alterado depois no painel
UsernameNome de usuário do administrador. Não use admin, pois é fácil de adivinhar (este exemplo serve apenas para demonstração)
PasswordSenha do administrador; o WordPress mostra o nível de segurança
Your EmailE-mail do administrador, usado para receber notificações e redefinir a senha
Search engine visibilitySe 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:

Tela de instalação bem-sucedida do WordPress
Instalação concluída. Clique em Log In para acessar a página de login
Página de login do WordPress
Página de login http://localhost:8080/wp-login.php

Entre 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:

Painel de administração do WordPress 7.1.3
Painel de administração do WordPress (Dashboard)

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

Página pública do site WordPress
Página pública do site (quando você está conectado, a barra de ferramentas de administração aparece no topo)

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:

Página de upload do WordPress mostrando Maximum upload file size: 64 MB
A página Upload Media mostra o limite de 64 MB na parte inferior

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:

Tela de login do phpMyAdmin
Tela de login do phpMyAdmin, com o servidor definido como db por PMA_HOST

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

phpMyAdmin exibindo as tabelas do banco de dados wordpress
Tabelas do banco de dados wordpress

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

VolumeConteúdo
wordpress_db_dataBanco de dados MySQL: posts, páginas, configurações, usuários e comentários
wordpress_wp_dataArquivos 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 em wordpress.sql e pode ser ignorado.
  • O início de wordpress.sql contém MySQL dump … Distrib 8.4.11, o que indica que a exportação foi concluída com sucesso.
  • $(basename "$PWD")_wp_data monta o nome do Volume wordpress_wp_data. Se o nome da pasta for diferente, confirme com docker volume ls.
  • :ro indica 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-apache acompanha 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 ports e não deixe o phpMyAdmin acessível pela internet.
  • Não use admin como 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 .env para o Git.

Resumo

  • Gerencie o WordPress e o MySQL com Compose. Os dados ficam nos volumes db_data e wp_data, respectivamente.
  • Na verificação de integridade do MySQL, use -h 127.0.0.1 para 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