14 KiB
🗄️ Guia de Provisionamento e Tuning de Dados: VPS 3 (newwhats)
Este documento centraliza as instruções práticas de configuração, tuning e provisionamento para o banco de dados principal de produção (PostgreSQL) e o cache de alta performance (DragonflyDB) hospedados na VPS 3 dedicada (especificações físicas: 8 GB de RAM e 4 núcleos de CPU).
🏛️ Divisão e Partilha Fisiológica de Recursos (Capacidade: 8 GB RAM / 4 CPUs)
Para garantir estabilidade absoluta do sistema e impedir que oscilações no tráfego de mensagens do WhatsApp causem o encerramento forçado de serviços pelo OOM (Out Of Memory Killer) do Linux, o hardware é segmentado de forma cirúrgica:
| Componente | Memória Alocada | Threads / CPUs | Função / Justificativa |
|---|---|---|---|
| PostgreSQL shared_buffers | 2.0 GB (25%) | Automático (Host) | Cache interno nativo de tabelas e índices de negócio do PostgreSQL. |
| PostgreSQL work_mem & OS | 2.2 GB (~27%) | Automático (Host) | Ordenações locais de queries, conexões e buffers de escrita do banco. |
DragonflyDB --memlimit_gb |
3.0 GB (~38%) | --num_threads 2 |
Armazenamento seguro de sessões de WhatsApp, presenças e QR codes ativos. |
| Sistema Operacional (SO) & Redes | 800 MB (~10%) | Reservado (2 CPUs) | Processamento da rede VPN WireGuard, kernel e deamon de firewall. |
Important
Tuning de CPU: O DragonflyDB é multi-threaded por natureza. Definir
--num_threads 2confina a execução do cache a apenas 2 núcleos, deixando 2 núcleos de processamento físico totalmente livres para as consultas SQL do PostgreSQL e para a criptografia do túnel Wireguard.
🚪 Escolha Estratégica do Temporal: Opção B (Temporal Server na VPS 5)
O Temporal Server possui uma pegada de RAM ativa que consome entre 400 MB a 800 MB em produção. Rodá-lo na VPS 3 deixaria a máquina no limite crítico de recursos físicos (apenas ~600 MB livres de folga).
Portanto, adota-se a Opção B: Hospedar o Temporal Server na VPS 5 (Aplicação):
- Ganho de Estabilidade: Preserva a VPS 3 exclusivamente como um Data Appliance de alta performance (Postgres + DragonflyDB).
- Latência Zero de API: Como o Temporal Worker roda ao lado do backend Express na VPS 5, colocá-los na mesma máquina permite que a comunicação entre Worker e Server aconteça via
localhost, eliminando overhead de rede VPN. - Persistência: O Temporal Server na VPS 5 continuará salvando seus dados persistentes de workflows (agenda/reputação) de forma segura no database dedicado
temporalna VPS 3 via túnel privado.
🗄️ 1. Separação de Databases e Privilégios no PostgreSQL
O banco de dados do negócio (newwhats) e a infraestrutura interna do orquestrador (temporal) são isolados fisicamente em databases independentes para evitar conflito de migrações (Prisma/Knex vs temporal-sql-tool), facilitar backups por tabela e prover auditoria de acessos.
Acesse o console do PostgreSQL (sudo -u postgres psql) e execute o script SQL abaixo:
-- ====================================================
-- 1. CRIAÇÃO DE DATABASES INDEPENDENTES
-- ====================================================
CREATE DATABASE newwhats;
CREATE DATABASE temporal;
-- ====================================================
-- 2. CRIAÇÃO DOS USUÁRIOS/ROLES ESTREITOS
-- ====================================================
CREATE USER newwhats_user WITH PASSWORD 'SuaSenhaForteNewwhatsAqui';
CREATE USER temporal_user WITH PASSWORD 'SuaSenhaForteTemporalAqui';
-- ====================================================
-- 3. REVOGAÇÃO DE ACESSOS PÚBLICOS PADRÃO (ZERO-TRUST)
-- ====================================================
REVOKE ALL ON DATABASE newwhats FROM PUBLIC;
REVOKE ALL ON DATABASE temporal FROM PUBLIC;
-- ====================================================
-- 4. ATRIBUIÇÃO DE CONEXÕES EXCLUSIVAS
-- ====================================================
GRANT CONNECT ON DATABASE newwhats TO newwhats_user;
GRANT CONNECT ON DATABASE temporal TO temporal_user;
-- ====================================================
-- 5. CONFIGURAÇÃO DE PRIVILÉGIOS GRANULARES
-- ====================================================
-- Conecte no banco 'newwhats' (\c newwhats) e execute:
GRANT USAGE ON SCHEMA public TO newwhats_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO newwhats_user;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO newwhats_user;
ALTER DATABASE newwhats OWNER TO newwhats_user;
-- Conecte no banco 'temporal' (\c temporal) e execute:
-- O temporal-sql-tool precisa de privilégios plenos dentro de seu banco para autogerenciar tabelas
GRANT ALL PRIVILEGES ON DATABASE temporal TO temporal_user;
ALTER DATABASE temporal OWNER TO temporal_user;
📊 2. Hardening da Configuração do PostgreSQL (pg_hba.conf)
Edite o arquivo /etc/postgresql/18/main/pg_hba.conf para garantir que o acesso ao banco de dados seja liberado apenas para os papéis designados originados da rede interna da VPN Wireguard:
# TYPE DATABASE USER ADDRESS METHOD
# 1. Permissões locais do sistema operacional (Apenas Root local)
local all postgres peer
# 2. Permitir que o backend (VPS 5) conecte apenas no database de negócio
host newwhats newwhats_user 10.99.0.5/32 scram-sha-256
# 3. Permitir que o orquestrador Temporal (VPS 5) conecte apenas no database temporal
host temporal temporal_user 10.99.0.5/32 scram-sha-256
# 4. Permitir conexões de replicação da VPS 4 (Staging/Replica)
host replication replicator 10.99.0.4/32 scram-sha-256
# 5. Bloqueio preventivo total para qualquer outro IP ou usuário
host all all 0.0.0.0/0 reject
Para aplicar as alterações:
sudo systemctl reload postgresql
🚀 3. Provisionamento do DragonflyDB (Systemd)
O DragonflyDB roda nativamente como um serviço leve do sistema, configurado com escuta restrita e controle estrito de memória física.
🛠️ Configuração do Serviço /etc/systemd/system/dragonfly.service:
Crie o arquivo de configuração de unidade do Systemd:
[Unit]
Description=DragonflyDB Cache Server
After=network.target
Wants=network-online.target
[Service]
Type=simple
User=dragonfly
Group=dragonfly
# Inicialização endurecida e otimizada para 8 GB RAM / 4 CPUs
ExecStart=/usr/local/bin/dragonfly \
--bind 10.99.0.3 \
--port 6379 \
--memlimit_gb 3 \
--num_threads 2 \
--save_schedule "" \
--logtostdout \
--requirepass SENHA_DRAGONFLY_PRODUCAO
Restart=always
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Note
Hardening de Escuta: O parâmetro
--bind 10.99.0.3substitui o padrão inseguro0.0.0.0. Isso força o DragonflyDB a escutar exclusivamente as requisições que transitam por dentro do túnel privado do Wireguard, impossibilitando tentativas de conexão direta a partir da internet pública.
🏁 Passos de ativação do serviço:
- Certifique-se de criar o usuário dedicado do sistema:
sudo useradd -r -s /bin/false dragonfly - Recarregue os daemons e ative o DragonflyDB:
sudo systemctl daemon-reload sudo systemctl enable dragonfly sudo systemctl start dragonfly
🏛️ 4. Centralização de Múltiplos Projetos (Database Appliance)
Centralizar os bancos de dados de todos os seus projetos (ex: google.com, facebook.com, newwhats) na VPS 3 dedicada, mantendo as aplicações e frontends isolados na VPS 1 (ou outras VPSs de app), é uma excelente decisão de design.
Isso separa a computação volátil das aplicações (onde acontecem picos de tráfego, deploys, memory leaks e builds pesados) da consistência estável da camada de persistência de dados.
⚠️ Regras de Segurança e Isolamento Mandatórias:
Para operar esse modelo compartilhado com segurança de nível corporativo e evitar que uma falha em um projeto comprometa ou degrade os outros (efeito Noisy Neighbor):
1. Isolamento Lógico Absoluto (Databases & Roles Independentes)
Nunca use o mesmo banco de dados ou o mesmo usuário PostgreSQL para projetos distintos. Cada projeto deve ter seu banco de dados próprio e seu usuário com privilégios restritos ao seu respectivo banco.
PostgreSQL (VPS 3)
├── database: google_db ──> OWNER: google_user (Apenas VPS 1 / 10.99.0.1)
├── database: facebook_db ──> OWNER: facebook_user (Apenas VPS 1 / 10.99.0.1)
└── database: newwhats ──> OWNER: newwhats_user (Apenas VPS 5 / 10.99.0.5)
2. Configuração do pg_hba.conf para Múltiplos Projetos:
Edite o arquivo /etc/postgresql/18/main/pg_hba.conf para mapear de forma cirúrgica as origens permitidas para cada projeto:
# TYPE DATABASE USER ADDRESS METHOD
# 1. Permissões de Administração local
local all postgres peer
# 2. Projeto GOOGLE (Frontend/Backend na VPS 1 -> Banco na VPS 3)
host google_db google_user 10.99.0.1/32 scram-sha-256
# 3. Projeto FACEBOOK (Frontend/Backend na VPS 1 -> Banco na VPS 3)
host facebook_db facebook_user 10.99.0.1/32 scram-sha-256
# 4. Projeto NEWWHATS (Backend na VPS 5 -> Banco na VPS 3)
host newwhats newwhats_user 10.99.0.5/32 scram-sha-256
# 5. Permitir conexões de replicação da VPS 4 (Staging/Replica)
host replication replicator 10.99.0.4/32 scram-sha-256
# 6. BLOQUEIO PADRÃO TOTAL (Zero-Trust)
host all all 0.0.0.0/0 reject
3. Gestão de Pools de Conexão no Node.js (Prisma/Knex)
Cada aplicação Node.js aberta na VPS 1 tentará criar um pool de conexões persistentes. Se muitos projetos rodarem simultaneamente, as conexões ativas podem saturar a memória RAM da VPS 3 (cada conexão ativa no Postgres é um processo físico consumindo ~10MB-20MB de RAM).
- Solução: Restrinja o tamanho máximo de pool nas variáveis de ambiente
.envde cada projeto na VPS 1:# Exemplo de limite de conexões no Prisma DATABASE_URL="postgresql://google_user:SENHA@10.99.0.3:5432/google_db?connection_limit=10" - PgBouncer (Avançado): Se o número de projetos escalonar para dezenas de aplicações na VPS 1, configure o PgBouncer na VPS 3 para multiplexar centenas de conexões virtuais em poucas conexões físicas reais do Postgres, reduzindo drasticamente o consumo de RAM.
🚀 5. Otimização de Performance e Tuning do PostgreSQL 18
Para aproveitar ao máximo os 8 GB de RAM e 4 núcleos de CPU da VPS 3 (Data Appliance) e garantir o processamento rápido e estável de dados para o newwhats e o giteadb, aplicamos um tuning avançado nativo.
As configurações foram modularizadas no arquivo /etc/postgresql/18/main/conf.d/tuning.conf para manter o postgresql.conf limpo e facilitar a portabilidade:
# ==========================================
# PostgreSQL Performance Tuning Configuration
# Optimized for 8 GB RAM / 4 CPU Cores
# ==========================================
# Memory Configuration
shared_buffers = 2GB
effective_cache_size = 6GB
maintenance_work_mem = 512MB
work_mem = 10MB
# Write-Ahead Log (WAL) Configuration
checkpoint_completion_target = 0.9
wal_buffers = 16MB
min_wal_size = 1GB
max_wal_size = 4GB
# Disk and Query Planner Settings (assuming SSD/NVMe)
random_page_cost = 1.1
effective_io_concurrency = 200
default_statistics_target = 100
# Worker Process and Parallelism Settings
max_worker_processes = 4
max_parallel_workers_per_gather = 2
max_parallel_workers = 4
max_parallel_maintenance_workers = 2
# Connections Configuration
max_connections = 100
🏁 Passos de ativação e validação:
# Reiniciar o serviço do cluster 18-main
sudo systemctl restart postgresql@18-main.service
# Confirmar os parâmetros carregados
sudo -u postgres psql -c "SHOW shared_buffers; SHOW effective_cache_size; SHOW work_mem;"
🧁 6. Resiliência de Inicialização do Gitea e DragonflyDB (Non-local Bind)
🔴 O Problema do Boot Sequencial
Como o Gitea (HTTP_ADDR = 10.99.0.3) e o DragonflyDB (--bind 10.99.0.3) escutam exclusivamente no IP interno da VPN Wireguard, ocorria uma falha de bind no reboot:
- O systemd inicializava estes serviços alguns milissegundos antes que a interface VPN (
wg0) estivesse totalmente ativa e com o IP associado. - Isso resultava no erro
bind: cannot assign requested address. - No caso do Gitea, ele falhava silenciosamente mantendo o processo de gerenciamento ativo, o que impedia o systemd de perceber a queda e reiniciar o serviço automaticamente.
🛡️ Solução Permanente Implementada
1. Configuração de Kernel: Non-local Bind
Ativamos uma diretiva de kernel para permitir que os daemons executem o bind em IPs de interfaces que ainda não estejam totalmente ativas no momento do boot:
# Ativar imediatamente
sudo sysctl -w net.ipv4.ip_nonlocal_bind=1
# Persistir para reboots futuros
echo "net.ipv4.ip_nonlocal_bind=1" | sudo tee -a /etc/sysctl.conf
2. Dependência no Systemd do Gitea
Atualizamos a unidade /etc/systemd/system/gitea.service para exigir que a rede esteja completamente online antes do início do Gitea:
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target network.target network-online.target postgresql.service
Wants=network-online.target
Após atualizar, execute: sudo systemctl daemon-reload
3. Dependência no Systemd do DragonflyDB (Override Nativo)
Criamos um arquivo de override limpo para o DragonflyDB em /etc/systemd/system/dragonfly.service.d/override.conf:
[Unit]
After=network-online.target
Wants=network-online.target
Após criar, execute: sudo systemctl daemon-reload