Tutoriais de VPS
Instalar WordPress em VPS (2026): Docker, MariaDB, HTTPS com Caddy, backups e hardening de segurança
Monte do zero um WordPress que funcione a longo prazo em uma VPS: implante WordPress e MariaDB com Docker Compose, configure HTTPS automático com Caddy e trate por completo o e-mail SMTP, os backups de banco de dados e arquivos, o rollback de atualizações, o hardening de segurança e as falhas comuns.

Instalar WordPress em VPS (2026): Docker, MariaDB, HTTPS com Caddy, backups e hardening de segurança
Se você quer um blog, um site corporativo ou um site independente de conteúdo, o WordPress continua sendo uma das opções mais comuns em VPS, e sua demanda de busca segue entre as mais estáveis. O que realmente mantém um site funcionando de forma estável a longo prazo não é abrir o assistente de instalação, mas configurar de uma vez a persistência do banco de dados, o HTTPS, as atualizações, os backups, o e-mail e os limites de segurança.
Este artigo usa Ubuntu 24.04 LTS, Docker Compose, a imagem oficial do WordPress, MariaDB e Caddy como exemplo para implantar do zero um ambiente de produção de site único. O exemplo coloca o WordPress e o banco de dados na rede interna do Docker, a aplicação escuta apenas em uma porta local e o Caddy cuida do HTTPS público.
A configuração do WordPress depende do tema, dos plugins, das imagens e da concorrência. Não compre uma máquina pensando apenas em "conseguir instalar":
| Caso de uso | Configuração recomendada | Observações |
|---|---|---|
| Blog pessoal, site corporativo de apresentação | 2 núcleos, 4 GB, 50 GB SSD | Adequado para poucos plugins e tráfego baixo a médio |
| WooCommerce ou site de conteúdo | 4 núcleos, 8 GB, 100 GB NVMe | Deixa margem para PHP, MariaDB e cache |
| Multisite ou tráfego alto | 4-8 núcleos, 8-16 GB no mínimo | Exige teste de carga, armazenamento de objetos e planejamento de banco de dados separado |
Prepare um domínio com antecedência, por exemplo www.example.com, e aponte os registros A / AAAA para a VPS. O firewall deve abrir apenas SSH, 80 e 443; não exponha a porta 3306 do MariaDB à internet.
Instale o Docker Engine e o Compose v2 a partir do repositório oficial do Docker e confirme que os comandos estão disponíveis:
docker --version
docker compose version
Crie um diretório dedicado e restrinja as permissões dos arquivos de configuração:
sudo mkdir -p /opt/wordpress/backups
sudo chown -R "$USER":"$USER" /opt/wordpress
cd /opt/wordpress
Gere uma senha de banco de dados:
openssl rand -hex 32
openssl rand -hex 32
nano .env
chmod 600 .env
Escreva /opt/wordpress/.env:
MYSQL_ROOT_PASSWORD=替换为第一组随机值
MYSQL_PASSWORD=替换为第二组随机值
WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wordpress
WORDPRESS_DB_HOST=db:3306
WORDPRESS_DEBUG=0
Não faça commit de .env no Git nem exponha a senha em chats, tickets ou capturas de tela.
Crie /opt/wordpress/compose.yaml:
services:
db:
image: mariadb:11.4
container_name: wordpress-db
restart: unless-stopped
env_file:
- .env
environment:
MARIADB_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:?set MYSQL_ROOT_PASSWORD in .env}"
MARIADB_DATABASE: "${WORDPRESS_DB_NAME:?set WORDPRESS_DB_NAME in .env}"
MARIADB_USER: "${WORDPRESS_DB_USER:?set WORDPRESS_DB_USER in .env}"
MARIADB_PASSWORD: "${MYSQL_PASSWORD:?set MYSQL_PASSWORD in .env}"
volumes:
- wordpress_db:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"]
interval: 10s
timeout: 5s
retries: 20
start_period: 30s
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --max-allowed-packet=64M
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
wordpress:
image: wordpress:6-php8.3-apache
container_name: wordpress
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:8080:80"
env_file:
- .env
environment:
WORDPRESS_DB_HOST: "${WORDPRESS_DB_HOST:?set WORDPRESS_DB_HOST in .env}"
WORDPRESS_DB_USER: "${WORDPRESS_DB_USER:?set WORDPRESS_DB_USER in .env}"
WORDPRESS_DB_PASSWORD: "${MYSQL_PASSWORD:?set MYSQL_PASSWORD in .env}"
WORDPRESS_DB_NAME: "${WORDPRESS_DB_NAME:?set WORDPRESS_DB_NAME in .env}"
WORDPRESS_DEBUG: "${WORDPRESS_DEBUG:-0}"
WORDPRESS_CONFIG_EXTRA: |
if (isset($$_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($$_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) {
$$_SERVER['HTTPS'] = 'on';
}
define('FORCE_SSL_ADMIN', true);
volumes:
- wordpress_data:/var/www/html
healthcheck:
test: ["CMD-SHELL", "php -r '$$c=@fsockopen(\"127.0.0.1\",80,$$e,$$s,5); exit($$c ? 0 : 1);'"]
interval: 30s
timeout: 10s
retries: 10
start_period: 60s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
volumes:
wordpress_db:
name: wordpress_db
wordpress_data:
name: wordpress_data
O WordPress se vincula apenas a 127.0.0.1:8080, e o MariaDB não tem configuração de ports, portanto o banco de dados não fica exposto diretamente à internet. Antes de uma atualização formal, fixe a série de imagens e verifique a compatibilidade de WordPress, PHP e MariaDB; não use latest a longo prazo.
Inicie e verifique:
docker compose config >/dev/null
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 wordpress db
curl -I http://127.0.0.1:8080/wp-login.php
Quando os dois serviços estiverem saudáveis, configure o proxy reverso. Não execute docker compose down -v durante a inicialização inicial; ele apaga o volume do banco de dados.
Edite /etc/caddy/Caddyfile:
www.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:8080
request_body {
max_size 64MB
}
}
Verifique e recarregue o Caddy:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -I https://www.example.com/wp-login.php
O Caddy obtém e renova os certificados automaticamente e encaminha X-Forwarded-Proto. O WORDPRESS_CONFIG_EXTRA no Compose permite que o WordPress reconheça corretamente o HTTPS externo. O "Endereço do site" e o "Endereço do WordPress" no painel administrativo ainda devem usar https://www.example.com, caso contrário ocorrerão conteúdo misto, loops de login ou redirecionamentos constantes no painel. Para detalhes do proxy reverso, consulte Guia completo do proxy reverso do Caddy em VPS.
Abra https://www.example.com no navegador e preencha o título do site, o nome de usuário administrador, uma senha forte e um e-mail dedicado. Não defina o nome de usuário administrador como admin nem use a mesma senha da VPS ou do e-mail.
Trate destas configurações imediatamente após a instalação:
- Confirme que a "Visibilidade nos mecanismos de busca" corresponde ao seu plano de lançamento;
- Exclua posts, páginas, temas e plugins não usados padrão;
- Defina os links permanentes como "Nome do post" e depois teste se os links antigos precisam de redirecionamento;
- Defina o fuso horário, o idioma e os tamanhos de miniatura de mídia corretos;
- Adicione uma página de política de privacidade do site nas configurações de privacidade;
- Ative a autenticação de dois fatores para a conta de administrador (quando o plugin ou o serviço de hospedagem oferecer suporte).
Não instale dezenas de plugins de "otimização" logo de início. Cada plugin adicional aumenta o custo de execução de PHP, consultas ao banco de dados, atualizações e auditoria de segurança.
O wp_mail() padrão do WordPress depende da capacidade de e-mail do servidor, e a porta 25 é restrita em muitas VPS, o que faz com que redefinições de senha, notificações de formulários e e-mails de pedidos se percam. Sites de produção devem usar um serviço SMTP confiável, configurar credenciais dedicadas por meio de um plugin SMTP e testar:
- Redefinição de senha do administrador;
- Convites de novos usuários ou notificações de registro;
- Formulários de contato e notificações de pedidos;
- Consistência de SPF, DKIM, DMARC e domínio do remetente.
Não grave a senha mestra do seu e-mail pessoal no WordPress; prefira senhas específicas de aplicativo ou uma conta SMTP dedicada.
O banco de dados guarda posts, usuários, configurações e pedidos; o volume wordpress_data guarda temas, plugins, imagens enviadas e wp-config.php. Fazer backup apenas do banco de dados faz com que os arquivos de mídia se percam após a restauração; fazer backup apenas dos arquivos deixa posts e dados de usuários incompletos.
Backup do banco de dados:
cd /opt/wordpress
mkdir -p backups
docker compose exec -T db sh -c \
'mariadb-dump --single-transaction --quick --routines --triggers \
-u root -p"$MARIADB_ROOT_PASSWORD" "$MARIADB_DATABASE"' \
| gzip > "backups/wordpress-db-$(date +%F-%H%M).sql.gz"
Backup do volume de arquivos do WordPress:
docker run --rm \
-v wordpress_data:/source:ro \
-v "$PWD/backups:/backup" \
alpine sh -c 'tar -C /source -czf /backup/wordpress-data.tar.gz .'
Copie pelo menos um backup para outra máquina ou armazenamento de objetos, restrinja as permissões de acesso e verifique periodicamente. Você pode consultar Simulação de backup e restauração em VPS para estabelecer um processo criptografado, externo e de aceitação da restauração.
Ao restaurar, primeiro interrompa as gravações do WordPress, restaure o volume de arquivos e o banco de dados e depois inicie a aplicação. A aceitação completa deve incluir login do administrador, posts, imagens, links permanentes, upload de mídia e e-mail, e não apenas se a página inicial abre.
O núcleo do WordPress, os temas, os plugins e o banco de dados podem sofrer mudanças estruturais. Faça backup antes de atualizar e registre as versões atuais:
docker compose exec wordpress php -r \
'include "/var/www/html/wp-includes/version.php"; echo $wp_version, PHP_EOL;'
docker compose images
docker compose ps
Atualização das imagens de contêiner:
docker compose config >/dev/null
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=200 wordpress
Após a atualização, verifique login, publicação de posts, upload de mídia, e-mails de formulários e cache do front-end. Atualize os plugins aos poucos; se aparecer tela branca ou erro 500, reverta primeiro a mudança mais recente em vez de atualizar todos os plugins de uma vez.
Não use docker compose down -v para resolver erros do WordPress nem exclua diretamente os volumes wordpress_data ou wordpress_db sem um backup.
No mínimo, você deve:
- Usar chaves SSH e um usuário sudo comum, e liberar apenas as portas necessárias no firewall da VPS;
- Usar senhas fortes e autenticação de dois fatores para o administrador do WordPress;
- Excluir plugins e temas desativados e não instalar plugins pirateados de origem desconhecida;
- Restringir
/xmlrpc.php, o endpoint de login e as tentativas de força bruta no painel, usando WAF ou limitação de taxa quando necessário; - Atualizar periodicamente WordPress, PHP, temas e plugins, mantendo um backup recuperável antes de atualizar;
- Não mapear a porta do MariaDB para a internet nem vazar senhas de banco de dados em posts, logs ou tickets;
- Configurar monitoramento para logs do Docker, espaço em disco e certificados HTTPS.
Se o site já estiver lento, diagnostique PHP-FPM, OPcache, Redis, cache e consultas lentas conforme O que fazer quando o WordPress em VPS está lento. Não trate plugins de cache como solução universal para falta de recursos de banco de dados ou do host.
docker compose ps
curl -I http://127.0.0.1:8080/wp-login.php
docker compose logs --tail=200 wordpress
sudo journalctl -u caddy --no-pager -n 100
Confirme que o contêiner do WordPress ainda está em execução, que o vínculo de porta é 127.0.0.1:8080 e verifique se o contêiner foi OOM Killed por falta de memória.
O nome de host do banco de dados dentro da rede do Compose é db, não localhost. Verifique se o usuário, a senha, o nome do banco de dados e o volume de dados existente em .env são consistentes:
docker compose logs --tail=200 db
docker compose exec wordpress getent hosts db
docker compose config
Alterar .env não muda automaticamente a senha de um usuário do MariaDB já inicializado; nesse caso, use comandos de gerenciamento do banco de dados para alterá-la de forma sincronizada, ou restaure a partir de um backup, em vez de excluir o volume e começar de novo.
Confirme que o Caddy encerra o HTTPS, que as duas URLs do site do WordPress são HTTPS e limpe o cache do plugin e os cookies do navegador. Não configure ao mesmo tempo modos SSL e regras de redirecionamento conflitantes com uma CDN como a Cloudflare.
Primeiro verifique o request_body max_size do Caddy, depois o upload_max_filesize, o post_max_size e o limite de memória do WordPress no PHP. Antes de aumentar os limites, confirme a capacidade de disco e de backup para evitar que um único upload esgote o espaço da VPS.
- O WordPress escuta apenas em
127.0.0.1:8080e o MariaDB não está exposto à internet - Domínio, HTTPS do Caddy e URLs do site do WordPress estão todos consistentes
- Senha forte do administrador, autenticação de dois fatores e privilégio mínimo estão configurados
- Os testes de redefinição de senha por SMTP, de formulários ou de e-mails de pedidos foram bem-sucedidos
- Tanto o banco de dados quanto
wordpress_datatêm backups externos - Uma simulação de restauração foi concluída, verificando posts, imagens e login
- As versões estão fixadas e com backup antes das atualizações, e 502, 500 e espaço em disco são verificados após as atualizações
- Conteúdo padrão, plugins desativados e temas desnecessários foram excluídos
Depois de concluir estas etapas, esta instalação do WordPress tem uma base de produção sustentável. O Docker isola a aplicação, o Caddy cuida do HTTPS, o MariaDB cuida da persistência dos dados, e os backups, o e-mail e as atualizações de segurança determinam se o site pode realmente funcionar a longo prazo.