---
title: "Como instalar WordPress com Docker Compose na VPS"
description: "Suba WordPress e MariaDB com Docker Compose na VPS: volumes nomeados, rede interna, senhas em .env, proxy reverso com HTTPS, backup e atualização."
url: "https://streethosting.com.br/guias/vps/instalar-wordpress-docker-vps"
category: "vps"
slug: "instalar-wordpress-docker-vps"
datePublished: "2026-09-28"
dateModified: "2026-09-28"
author: "Equipe StreetHosting"
difficulty: "intermediario"
language: "pt-BR"
keywords:
  - "instalar wordpress docker"
  - "wordpress docker compose"
  - "wordpress mariadb docker"
  - "docker wordpress vps"
  - "backup volume docker wordpress"
---

# WordPress em containers: Compose, MariaDB e HTTPS na VPS

Com Docker Compose, WordPress e banco sobem com um comando e os dados ficam em volumes que sobrevivem a qualquer atualização. Veja o arquivo completo, o proxy com HTTPS e a rotina de backup.

> **Resposta rápida**
>
> Para **instalar WordPress com Docker**, crie um arquivo do Compose com dois serviços, wordpress e mariadb, cada um com volume nomeado para os dados, uma rede interna para o banco e as senhas em um arquivo .env. Publique o WordPress só em 127.0.0.1 e coloque o Nginx do host na frente com certificado Let's Encrypt. O backup é um dump do banco mais um arquivo compactado do volume de arquivos.

## Docker ou instalação nativa

As duas formas rodam o mesmo WordPress. A diferença está em como você instala, isola e atualiza cada parte.

| Critério | Docker Compose | Instalação nativa |
| --- | --- | --- |
| Tempo para subir | Minutos, a partir de um arquivo | Mais passos, pacote por pacote |
| Isolamento entre sites | Cada site com seus containers, banco e versão de PHP | Usuários e pools do PHP separados, feitos à mão |
| Consumo de RAM | Um pouco maior: cada site tem seu Apache e seu banco | Menor: serviços compartilhados entre os sites |
| Trocar a versão do PHP | Mudar a tag da imagem | Instalar outros pacotes no sistema |
| Recriar em outra VPS | Copiar a pasta e os volumes | Refazer a instalação e copiar os dados |
| Ajuste fino do servidor web | Por arquivos montados no container | Direto nos arquivos do sistema |

Docker compensa quando você quer versões fixas, vários sites isolados ou a possibilidade de recriar o ambiente idêntico em outra máquina. A instalação [nativa com Nginx, PHP FPM e MariaDB](https://streethosting.com.br/guias/vps/hospedar-wordpress-vps-nginx) tira mais desempenho de cada megabyte e dá acesso direto a cache de página no Nginx. Nenhuma das duas é errada.

## Preparar a VPS e o arquivo .env

Você precisa do Docker Engine com o plugin Compose. Se ainda não tem, siga [instalar Docker no Ubuntu da VPS](https://streethosting.com.br/guias/vps/instalar-docker-ubuntu-vps) e confira com `docker compose version`. O domínio também já deve apontar para o IP da VPS, porque o HTTPS depende disso. Crie a pasta do projeto e o arquivo de senhas:

```
sudo mkdir -p /srv/meusite
sudo chown $USER: /srv/meusite
cd /srv/meusite

# gere duas senhas diferentes
openssl rand -base64 24
openssl rand -base64 24

nano .env
chmod 600 .env
```

Conteúdo do `.env`, com as senhas geradas:

```
DB_PASSWORD=cole_a_primeira_senha
DB_ROOT_PASSWORD=cole_a_segunda_senha
```

Crie também o `uploads.ini`, que aumenta os limites do PHP dentro do container. A imagem oficial usa os valores padrão do PHP, pequenos demais para upload de vídeo, tema ou plugin grande:

```
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
```

> **Atenção**
>
> Se você versiona essa pasta no Git, coloque o `.env` no `.gitignore`. Senha de banco em repositório é um dos vazamentos mais comuns, e o histórico do Git guarda o arquivo mesmo depois de apagado.

## O arquivo do Compose explicado

Salve como `/srv/meusite/docker-compose.yml`:

```
name: meusite

services:
  db:
    image: mariadb:11.4
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: wordpress
      MARIADB_USER: wordpress
      MARIADB_PASSWORD: ${DB_PASSWORD}
      MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - interna
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s

  wordpress:
    image: wordpress:php8.3-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
    volumes:
      - wp_data:/var/www/html
      - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
    ports:
      - "127.0.0.1:8080:80"
    networks:
      - interna
      - saida

volumes:
  db_data:
  wp_data:

networks:
  interna:
    internal: true
  saida:
```

- **name:** fixa o nome do projeto. Os volumes passam a se chamar `meusite_db_data` e `meusite_wp_data`, independentemente do nome da pasta, o que simplifica backup e restauração.
- **Volumes nomeados:** os dados moram em volumes gerenciados pelo Docker, não dentro do container. Recriar ou atualizar o container não toca neles. O banco fica em `db_data`; núcleo, temas, plugins, uploads e a configuração do WordPress ficam em `wp_data`.
- **Rede interna:** a rede `interna` não tem rota para fora. O MariaDB só existe nela e não publica porta, então nada fora do WordPress consegue alcançar o banco. O WordPress também entra na rede `saida` para baixar plugins, temas e atualizações.
- **Variáveis:** o Compose lê o `.env` da mesma pasta e substitui as referências às senhas. O arquivo do Compose pode ir para o Git sem expor nada.
- **Healthcheck:** o WordPress só sobe depois que o MariaDB aceita conexões, o que evita o erro de conexão com o banco na primeira inicialização.
- **Porta em 127.0.0.1:** o Docker grava regras próprias no firewall do kernel, e uma porta publicada em todas as interfaces ignora o UFW. Presa ao loopback, ela só é alcançada pelo proxy da própria VPS.

Uma variação comum é trocar o volume `wp_data` por uma pasta do host, como `./wp:/var/www/html`. Funciona e facilita editar um tema por SFTP, mas os arquivos passam a pertencer ao usuário numérico do container, e qualquer ajuste de permissão feito no host afeta o site. Se você não pretende mexer nos arquivos por fora, o volume nomeado dá menos trabalho e é o que os comandos de backup deste guia esperam.

> **Dica**
>
> A tag `php8.3-apache` acompanha a versão mais recente do WordPress com PHP 8.3. Para fixar a versão principal, use o formato `7-php8.3-apache`. Confira as tags disponíveis no Docker Hub antes de trocar, porque as versões de PHP oferecidas mudam com o tempo.

## Subir os containers e resolver erros

```
cd /srv/meusite
docker compose up -d
docker compose ps
docker compose logs -f wordpress
curl -I http://127.0.0.1:8080
```

O `docker compose ps` deve mostrar o banco como healthy e o WordPress rodando. O curl deve devolver um redirecionamento para a página de instalação. Na primeira subida, a imagem copia o WordPress para o volume e gera o arquivo de configuração com salts aleatórios, que ficam guardados no próprio volume.

Ainda não abra o instalador. Faça antes o proxy com HTTPS, para o WordPress gravar o endereço do site já com https e você não precisar corrigir URLs depois.

Se algo não subir, estes são os erros que mais aparecem nessa montagem e o que cada um costuma significar:

| Sintoma | Causa provável | Correção |
| --- | --- | --- |
| Error establishing a database connection | A senha do .env foi trocada depois da primeira subida. O MariaDB só lê essas variáveis ao criar o volume vazio | Volte a senha original no .env ou altere a senha do usuário dentro do banco com ALTER USER |
| Loop de redirecionamento ou página sem estilo | O proxy não avisa ao WordPress que a conexão original é HTTPS | Envie o cabeçalho de protocolo no server block, como mostrado abaixo, e recarregue o Nginx |
| 413 Request Entity Too Large no upload | Limite de corpo do Nginx do host menor que o arquivo | Ajuste client_max_body_size junto com o uploads.ini |
| WordPress pede dados de FTP para instalar plugin | Arquivos do volume com dono errado, comum depois de restaurar backup | Devolva a posse dos arquivos ao usuário do Apache no container |
| port is already allocated ao subir | Outra aplicação já usa a porta 8080 no loopback | Troque para 8081 no Compose e no proxy_pass |

Para o caso das permissões, o usuário do Apache na imagem oficial é o `www-data`, e um único comando resolve: `docker compose exec wordpress chown -R www-data:www-data /var/www/html`. Para ver o que o banco está dizendo, use `docker compose logs db`; a primeira inicialização registra ali a criação do usuário e do banco.

## Proxy reverso com HTTPS

O Nginx roda no host, recebe as portas 80 e 443 e repassa para o container. Instale com `sudo apt install -y nginx certbot python3-certbot-nginx` e crie `/etc/nginx/sites-available/seu-dominio.com.br`:

```
server {
    listen 80;
    server_name seu-dominio.com.br www.seu-dominio.com.br;
    client_max_body_size 64M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```

```
sudo ln -s /etc/nginx/sites-available/seu-dominio.com.br /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo ufw allow 'Nginx Full'
sudo certbot --nginx -d seu-dominio.com.br -d www.seu-dominio.com.br
```

O cabeçalho `X-Forwarded-Proto` é o detalhe que mais quebra instalações. O arquivo de configuração que a imagem oficial gera marca a requisição como HTTPS quando esse cabeçalho diz https. Sem ele, o WordPress acha que está em HTTP e entra em loop de redirecionamento ou carrega CSS em HTTP, bloqueado pelo navegador. Os fundamentos do proxy estão em [Nginx como reverse proxy na VPS](https://streethosting.com.br/guias/vps/configurar-nginx-reverse-proxy-vps). Se você prefere uma interface web para gerenciar domínios e certificados, o [Nginx Proxy Manager](https://streethosting.com.br/guias/vps/instalar-nginx-proxy-manager-vps) cumpre o mesmo papel.

Com o certificado emitido, abra `https://seu-dominio.com.br` e conclua o instalador. Plugins de segurança que registram o IP do visitante devem ser configurados para ler o `X-Forwarded-For`, porque para o Apache do container toda conexão vem do proxy.

## Backup dos volumes

São duas cópias: o banco, por dump, e o volume de arquivos, por um arquivo compactado. Junte as duas em um script, para rodar à mão hoje e pelo cron depois. Crie `/usr/local/bin/backup-meusite.sh`:

```
#!/bin/sh
set -e
DESTINO=/srv/backups
DATA=$(date +%F)
mkdir -p "$DESTINO"
cd /srv/meusite

# banco: dump consistente sem parar o site
docker compose exec -T db sh -c 'exec mariadb-dump --single-transaction -uroot -p"$MARIADB_ROOT_PASSWORD" wordpress'   > "$DESTINO/wp-banco-$DATA.sql"

# arquivos: núcleo, temas, plugins, uploads e configuração
docker run --rm -v meusite_wp_data:/dados:ro -v "$DESTINO":/backup alpine   tar -czf "/backup/wp-arquivos-$DATA.tar.gz" -C /dados .

# mantém sete dias de cópias locais
find "$DESTINO" -name 'wp-*' -mtime +7 -delete
```

```
sudo chmod 700 /usr/local/bin/backup-meusite.sh
sudo /usr/local/bin/backup-meusite.sh
ls -lh /srv/backups

# agendar todo dia às 3h30: abra o crontab do root
sudo crontab -e
# e acrescente esta linha no editor
30 3 * * * /usr/local/bin/backup-meusite.sh
```

Rode uma vez à mão e confira se os dois arquivos têm tamanho coerente antes de confiar no agendamento. O dump com `--single-transaction` gera uma cópia coerente do banco com o site no ar. Copiar os arquivos do volume do MariaDB com o serviço rodando pode produzir um backup que não abre. Para restaurar, o caminho é o inverso:

```
cd /srv/meusite
docker compose exec -T db sh -c 'exec mariadb -uroot -p"$MARIADB_ROOT_PASSWORD" wordpress'   < /srv/backups/wp-banco-AAAA-MM-DD.sql

docker run --rm -v meusite_wp_data:/dados -v /srv/backups:/backup alpine   sh -c "cd /dados && tar -xzf /backup/wp-arquivos-AAAA-MM-DD.tar.gz"
```

Falta a parte mais importante: tirar as cópias da VPS. Backup que mora no mesmo disco some junto com ele, e em uma VPS a rotina de backup é responsabilidade de quem administra o servidor. O guia de [backup automático da VPS com restic e cron](https://streethosting.com.br/guias/vps/automatizar-backup-vps-restic-cron) mostra como mandar a pasta de backups, criptografada, para outro servidor ou storage compatível com S3, com retenção e teste de restauração.

## Atualizar imagens sem perder dados

```
cd /srv/meusite
docker compose pull
docker compose up -d
docker image prune -f
```

O Compose recria só os containers cuja imagem mudou, e os volumes continuam onde estavam. Há um detalhe que confunde muita gente: a imagem do WordPress copia o núcleo para o volume apenas quando ele está vazio. Uma imagem nova atualiza PHP e Apache, mas o WordPress dentro do volume continua na mesma versão. Núcleo, plugins e temas se atualizam pelo painel, como em qualquer instalação.

- **MariaDB na mesma série:** a tag `11.4` recebe correções dentro da série com um simples pull.
- **MariaDB em outra série:** faça o dump antes, troque a tag e acrescente `MARIADB_AUTO_UPGRADE: "1"` ao ambiente do serviço, para a imagem atualizar as tabelas de sistema na subida.
- **Nova versão do PHP:** teste a tag nova em uma cópia do site antes de trocar em produção. Plugins antigos são o que costuma quebrar.

Quem prefere acompanhar containers, logs e volumes por uma interface pode instalar o [Portainer para gerenciar o Docker](https://streethosting.com.br/guias/vps/instalar-portainer-docker-vps), com o acesso protegido por HTTPS e senha forte.

## Qual VPS usar

Cada site em Docker soma um container do WordPress com Apache e um do MariaDB. Um site com tráfego modesto costuma ficar abaixo de 1 GB somando os dois; confira o consumo real com `docker stats` depois de alguns dias no ar. Com vários sites, multiplique: cinco projetos significam cinco bancos e cinco servidores web ocupando memória, mesmo que quatro deles recebam poucas visitas. Deixe também espaço em disco para as imagens, os volumes e as cópias locais do backup, que crescem junto com a pasta de uploads.

| Cenário | Plano de partida | Preço mensal |
| --- | --- | --- |
| Um site leve ou ambiente de testes | VPS Xeon 2 vCPU, 2 GB, 20 GB NVMe | R$ 23,00 |
| Um a três sites com cache | VPS Xeon 3 vCPU, 4 GB, 40 GB NVMe | R$ 40,00 |
| Loja ou site com muito conteúdo dinâmico | VPS Ryzen 2 vCPU, 4 GB DDR5, 40 GB NVMe | R$ 64,00 |
| Vários sites, cada um com sua pilha | VPS Xeon 6 vCPU, 8 GB, 80 GB NVMe | R$ 74,00 |

As duas linhas rodam em São Paulo com NVMe, acesso root, AntiDDoS incluso e ativação em até 60 segundos. A Xeon entrega mais vCPU por real para vários sites; a Ryzen 9 9950X, com clock de até 5,7 GHz, responde mais rápido nas páginas que não saem do cache. Veja todos os degraus na [página de VPS da StreetHosting](https://streethosting.com.br/vps).

## Perguntas frequentes

### Docker deixa o WordPress mais lento?

Não de forma perceptível. Containers rodam direto no kernel da VPS, sem uma camada extra de virtualização. A diferença vem da imagem oficial usar Apache com PHP embutido, que gasta mais memória por conexão do que Nginx com PHP FPM; com cache de página, o visitante raramente percebe.

### Os dados somem se eu apagar o container?

Não, desde que estejam em volumes. Parar, remover ou recriar containers mantém os volumes intactos. Eles só são apagados com docker compose down -v ou docker volume rm, então nunca use essas opções sem um backup recente.

### Como atualizar o WordPress que roda em Docker?

Núcleo, plugins e temas são atualizados pelo painel do WordPress, porque ficam no volume. Atualizar a imagem com docker compose pull renova PHP e Apache, mas não substitui os arquivos do WordPress que já estão no volume.

### Posso rodar vários sites WordPress com Docker na mesma VPS?

Pode. Crie uma pasta por site, cada uma com seu arquivo do Compose, seu nome de projeto e uma porta diferente em 127.0.0.1, e aponte um server block do Nginx do host para cada porta. Cada site fica com banco e versão de PHP próprios.

### Por que publicar a porta do WordPress só em 127.0.0.1?

Porque o Docker cria regras próprias no firewall do kernel, e uma porta publicada em todas as interfaces fica acessível pela internet mesmo com o UFW bloqueando. Em 127.0.0.1, só o Nginx da própria VPS alcança o container, e todo acesso externo passa pelo HTTPS.

## Guias relacionados

- [Como instalar Docker no Ubuntu 22.04 ou 24.04 em VPS (guia direto ao ponto)](https://streethosting.com.br/guias/vps/instalar-docker-ubuntu-vps.md)
- [Hospedar WordPress na VPS: Nginx, PHP 8.3 e MariaDB](https://streethosting.com.br/guias/vps/hospedar-wordpress-vps-nginx.md)
- [Como configurar o Nginx como reverse proxy na VPS](https://streethosting.com.br/guias/vps/configurar-nginx-reverse-proxy-vps.md)
- [Como configurar backup automático da VPS com restic e cron](https://streethosting.com.br/guias/vps/automatizar-backup-vps-restic-cron.md)
- [VPS para WordPress: como escolher RAM, CPU e disco](https://streethosting.com.br/guias/vps/escolher-vps-para-wordpress.md)

## Produtos citados

- https://streethosting.com.br/vps
- https://streethosting.com.br/vps/xeon
- https://streethosting.com.br/vps/ryzen

## Dados estruturados

```json
[
  {
    "@context": "https://schema.org",
    "@type": [
      "Article",
      "TechArticle"
    ],
    "headline": "WordPress em containers: Compose, MariaDB e HTTPS na VPS",
    "name": "Como instalar WordPress com Docker Compose na VPS",
    "abstract": "Com Docker Compose, WordPress e banco sobem com um comando e os dados ficam em volumes que sobrevivem a qualquer atualização. Veja o arquivo completo, o proxy com HTTPS e a rotina de backup.",
    "description": "Suba WordPress e MariaDB com Docker Compose na VPS: volumes nomeados, rede interna, senhas em .env, proxy reverso com HTTPS, backup e atualização.",
    "datePublished": "2026-09-28",
    "dateModified": "2026-09-28",
    "author": {
      "@type": "Organization",
      "name": "Equipe StreetHosting"
    },
    "publisher": {
      "@type": "Organization",
      "name": "StreetHosting",
      "url": "https://streethosting.com.br"
    },
    "inLanguage": "pt-BR",
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://streethosting.com.br/guias/vps/instalar-wordpress-docker-vps"
    }
  },
  {
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": [
      {
        "@type": "Question",
        "name": "Docker deixa o WordPress mais lento?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Não de forma perceptível. Containers rodam direto no kernel da VPS, sem uma camada extra de virtualização. A diferença vem da imagem oficial usar Apache com PHP embutido, que gasta mais memória por conexão do que Nginx com PHP FPM; com cache de página, o visitante raramente percebe."
        }
      },
      {
        "@type": "Question",
        "name": "Os dados somem se eu apagar o container?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Não, desde que estejam em volumes. Parar, remover ou recriar containers mantém os volumes intactos. Eles só são apagados com docker compose down -v ou docker volume rm, então nunca use essas opções sem um backup recente."
        }
      },
      {
        "@type": "Question",
        "name": "Como atualizar o WordPress que roda em Docker?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Núcleo, plugins e temas são atualizados pelo painel do WordPress, porque ficam no volume. Atualizar a imagem com docker compose pull renova PHP e Apache, mas não substitui os arquivos do WordPress que já estão no volume."
        }
      },
      {
        "@type": "Question",
        "name": "Posso rodar vários sites WordPress com Docker na mesma VPS?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Pode. Crie uma pasta por site, cada uma com seu arquivo do Compose, seu nome de projeto e uma porta diferente em 127.0.0.1, e aponte um server block do Nginx do host para cada porta. Cada site fica com banco e versão de PHP próprios."
        }
      },
      {
        "@type": "Question",
        "name": "Por que publicar a porta do WordPress só em 127.0.0.1?",
        "acceptedAnswer": {
          "@type": "Answer",
          "text": "Porque o Docker cria regras próprias no firewall do kernel, e uma porta publicada em todas as interfaces fica acessível pela internet mesmo com o UFW bloqueando. Em 127.0.0.1, só o Nginx da própria VPS alcança o container, e todo acesso externo passa pelo HTTPS."
        }
      }
    ]
  }
]
```
