Guia prático: como configurar failover ativo-passivo entre duas VPS com Keepalived, HAProxy e lsyncd para uploads sincronizados
Por Kevin Marcondes · Publicado em · 10 min de leitura
Como configurar failover ativo-passivo entre duas VPS com Keepalived, HAProxy e lsyncd para uploads sincronizados. Este guia mostra a topologia, pré-requisitos e a configuração passo a passo. Você terá um VIP flutuante com VRRP, HAProxy como entrada de tráfego e lsyncd para replicar uploads quase em tempo real via SSH. O foco é simplicidade e troca automática de nó.
O que é o failover ativo‑passivo com Keepalived, HAProxy e lsyncd?
Failover ativo‑passivo usa duas VPS. Uma atende (MASTER) e a outra fica em espera (BACKUP). O Keepalived move um IP virtual (VIP) entre os nós por VRRP. O HAProxy escuta no VIP e envia ao app local. O lsyncd replica uploads do MASTER para o BACKUP por SSH.
Essa arquitetura reduz indisponibilidade e mantém uploads consistentes. É direta e não exige orquestrador. Veja o papel de cada peça e pontos de atenção.
| Componente | Papel | Pontos de atenção |
|---|---|---|
| Keepalived (VRRP) | Move o VIP entre VPS | Unicast em nuvem; prioridade; healthchecks; ARP/GARP |
| HAProxy | Ponto de entrada HTTP/HTTPS no VIP | Health check do app; ip_nonlocal_bind |
| lsyncd (rsync/SSH) | Replica uploads do MASTER → BACKUP | Chaves SSH; exclusões; evitar split‑brain |
| Aplicação | Atende localmente no nó ativo | Uploads em diretório dedicado; permissões |
| Firewall/Kernel | Permite VRRP/announce do VIP | arp_announce/ignore; rotas; journald/logrotate |
Quais pré‑requisitos e limitações em VPS devo checar?
Verifique se as duas VPS compartilham a mesma sub‑rede ou suportam VIP/floating IP. Alguns provedores bloqueiam multicast e ARP gratuito. Quando não houver L2 comum, use VRRP em unicast e teste o anúncio do VIP.
Se o provedor bloquear ARP/VRRP, o failover de VIP não funcionará. Alternativa: automação de DNS com TTL baixo. Há trade‑offs de propagação. Garanta chaves SSH entre nós, NTP e um diretório exclusivo de uploads.
Para preparar o sistema e evitar gargalos de kernel e logs, consulte este checklist de VPS Debian para produção: checklist técnico de VPS Debian. Para retenção de logs do journald, veja também o guia de políticas: retensão e compactação do journald.
- Duas VPS na mesma sub‑rede ou suporte a VIP/floating IP
- Acesso root por SSH para instalar e configurar pacotes
- Relógio sincronizado (chrony ou systemd‑timesyncd)
- Diretório de uploads separado (ex.: /var/www/app/uploads)
- Portas: HTTP/HTTPS para HAProxy; VRRP unicast entre nós
- Rotina de rotação de logs para não encher disco
Preparar usuários, diretórios e chaves SSH para o lsyncd
Crie um usuário de sincronização com acesso restrito, ajuste permissões do diretório de uploads e troque chaves SSH. Faça backup do diretório de uploads antes de automatizar sincronização.
No exemplo, nó A = 10.0.0.10 (MASTER preferencial) e nó B = 10.0.0.11 (BACKUP). Ajuste IPs, caminhos e usuários à sua realidade.
# Em AMBAS as VPS (A e B):
sudo adduser --system --group --home /var/sync sync
sudo usermod -aG www-data sync
# Diretório de uploads da aplicação (se já existir, apenas ajuste permissões):
sudo mkdir -p /var/www/app/uploads
sudo chown -R www-data:www-data /var/www/app/uploads
sudo chmod 2755 /var/www/app/uploads # setgid para manter o grupo
# Gerar chave no nó A e autorizar no nó B (para rsync via SSH):
sudo -u sync mkdir -p /var/sync/.ssh && sudo chown -R sync:sync /var/sync/.ssh && sudo chmod 700 /var/sync/.ssh
sudo -u sync ssh-keygen -t ed25519 -C sync@vpsA -f /var/sync/.ssh/id_ed25519 -N ""
ssh-copy-id -i /var/sync/.ssh/id_ed25519.pub [email protected]
# Segurança no nó B (opcional avançado): restringir comandos no authorized_keys
# command="rrsync /var/www/app/uploads",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-ed25519 AAAA... sync@vpsA
Como configurar o Keepalived (VRRP) em unicast com VIP flutuante
Instale o Keepalived, habilite sysctl para ARP e ip_nonlocal_bind e crie uma instância VRRP por nó. Use prioridade maior no primário. Um vrrp_script derruba a prioridade quando o HAProxy parar.
Use scripts de notify para controlar o lsyncd: no MASTER, faça um rsync de aquecimento e inicie o lsyncd; no BACKUP/FAULT, pare o lsyncd. Ajuste IPs, interface e VIP.
# Em AMBAS as VPS (ajuste interface e IPs):
# /etc/sysctl.d/99-vrrp.conf
net.ipv4.ip_nonlocal_bind=1
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.default.arp_ignore=1
net.ipv4.conf.default.arp_announce=2
# Aplicar sysctl
# sysctl --system
# Instalar serviços essenciais
# apt-get update && apt-get install -y keepalived haproxy lsyncd
# /etc/keepalived/keepalived.conf (exemplo para o nó A - MASTER preferencial)
vrrp_script chk_haproxy {
script "/usr/bin/pgrep -x haproxy"
interval 2
fall 2
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 150 # nó A mais prioritário
advert_int 1
authentication {
auth_type PASS
auth_pass 7c0m53gr3t
}
unicast_src_ip 10.0.0.10
unicast_peer {
10.0.0.11
}
track_script {
chk_haproxy
}
virtual_ipaddress {
10.0.0.50/24 dev eth0 label eth0:vip
}
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"
}
# No nó B, mude:
# state BACKUP
# priority 100
# unicast_src_ip 10.0.0.11
# unicast_peer { 10.0.0.10 }
# notify.sh para iniciar/parar o lsyncd conforme o papel do nó
# /etc/keepalived/notify.sh
#-----------------------------------
#!/usr/bin/env bash
set -euo pipefail
ROLE="$1" # master|backup|fault
PEER_IP="10.0.0.11" # do ponto de vista do nó A; ajuste no B
SRC_DIR="/var/www/app/uploads"
DST="sync@${PEER_IP}:${SRC_DIR}"
LOGTAG="keepalived-notify"
case "$ROLE" in
master)
logger -t "$LOGTAG" "MASTER: warm-up rsync -> $DST"
rsync -az --inplace --partial "$SRC_DIR/" "$DST/" || true
systemctl restart lsyncd
;;
backup|fault)
logger -t "$LOGTAG" "${ROLE^^}: stopping lsyncd"
systemctl stop lsyncd || true
;;
*)
logger -t "$LOGTAG" "unknown role: $ROLE" ;;
esac
#-----------------------------------
# chmod 750 /etc/keepalived/notify.sh && chown root:root /etc/keepalived/notify.sh
# systemctl enable --now keepalived
Configurar o HAProxy para atender pelo VIP
O HAProxy escuta em 0.0.0.0; quando o VIP estiver no nó, os clientes chegarão por ele. O health check do backend sustenta o vrrp_script do Keepalived. Substitua a porta 8080 pela do seu app.
Para TLS e ACME, você pode ampliar depois. Veja ideias neste passo a passo: HAProxy com Let's Encrypt e healthchecks.
# /etc/haproxy/haproxy.cfg (mínimo funcional)
global
log /dev/log local0
maxconn 2000
daemon
defaults
mode http
log global
option httplog
timeout connect 5s
timeout client 30s
timeout server 30s
frontend fe_http
bind 0.0.0.0:80
http-request set-header X-Forwarded-Proto http
default_backend be_app
backend be_app
option httpchk GET /health
server app1 127.0.0.1:8080 check
# Valide e habilite
# haproxy -c -f /etc/haproxy/haproxy.cfg && systemctl enable --now haproxy
Como sincronizar uploads apenas no nó MASTER com lsyncd
O lsyncd observa alterações e dispara rsync via SSH do MASTER para o BACKUP. Para evitar split‑brain, ele deve rodar apenas no nó que detém o VIP. O notify.sh do Keepalived cuida disso.
Use exclusões para arquivos temporários e ative --inplace para reduzir escrita duplicada. Cuidado com --delete: só use após validar o sentido da sincronização.
-- /etc/lsyncd/lsyncd.lua
settings {
logfile = "/var/log/lsyncd.log",
statusFile = "/var/run/lsyncd.status",
nodaemon = false,
maxDelays = 5,
}
default.rsyncssh {
source = "/var/www/app/uploads",
host = "[email protected]", -- destino (nó B)
targetdir = "/var/www/app/uploads",
rsync = {
archive = true,
compress = true,
verbose = true,
_extra = { "--inplace", "--partial" }
-- Para espelhamento completo, adicione: "--delete" (use com cautela)
},
delay = 2,
excludeFrom = "/etc/lsyncd.exclude"
}
-- /etc/lsyncd.exclude (exemplo)
-- *.tmp
-- .*swp
-- .DS_Store
-- Habilite o serviço (start/stop será controlado pelo Keepalived):
-- systemctl enable lsyncd
Como testar o failover e confirmar que funcionou?
Verifique quem detém o VIP, faça um upload de teste e simule falha do serviço. O HAProxy deve expor uma rota /health simples. O VIP deve migrar em segundos quando o health check falhar.
Após estabilizar, valide se o arquivo de teste apareceu no nó BACKUP. Monitore logs para entender tempos de troca e sincronização.
# 1) Quem é o MASTER (deve mostrar 10.0.0.50 no nó ativo)
ip -br a | grep 10.0.0.50 || echo "VIP não está neste nó"
# 2) Teste HTTP pelo VIP
curl -sS http://10.0.0.50/health || echo "sem resposta"
# 3) Upload/arquivo de teste no MASTER e checar no BACKUP
TS=$(date +%s)
echo "ok-$TS" | sudo -u www-data tee /var/www/app/uploads/test-$TS.txt >/dev/null
ssh [email protected] "ls -l /var/www/app/uploads/test-$TS.txt"
# 4) Simule falha do HAProxy no MASTER e observe failover
sudo systemctl stop haproxy
sleep 3
curl -sS http://10.0.0.50/health || echo "sem resposta"
# 5) Logs úteis
journalctl -u keepalived -n 50 --no-pager
journalctl -u lsyncd -n 50 --no-pager
Boas práticas, observabilidade e problemas comuns
Monitore logs, uso de disco e latência de sincronização. Rotacione logs para não afetar o VRRP nem o lsyncd. Mantenha healthchecks simples e confiáveis. Evite que a aplicação aceite escritas no BACKUP.
Se algo falhar, revise rede, ARP/VRRP e permissões do diretório de uploads. Para riscos de split‑brain em cenários de dados, veja também esta visão de failover: evitar split‑brain em failover de PostgreSQL.
- Use healthchecks rápidos (/health) no HAProxy e track_script simples
- Prioridade do MASTER maior; não altere o virtual_router_id
- Libere firewall para VRRP unicast entre os IPs das VPS
- Cheque permissões do diretório (setgid e grupo da aplicação)
- Rotacione logs do systemd‑journald para evitar disco cheio
- Documente runbooks e teste o failover periodicamente
Perguntas frequentes
Preciso que as duas VPS estejam na mesma rede para o VIP funcionar?
Sim. Na maioria dos casos, as duas VPS precisam compartilhar a mesma sub‑rede ou usar o recurso de floating IP do provedor. Sem L2 comum ou suporte a ARP/VRRP, o VIP não falhará entre nós. Alternativa: automatizar DNS com TTL baixo, aceitando a propagação.
Como evitar split‑brain nos uploads com lsyncd?
Execute o lsyncd apenas no nó MASTER, controlado pelo notify do Keepalived. Faça um rsync de aquecimento ao assumir o MASTER e, se usar --delete, valide o sentido da sincronização. Evite a aplicação aceitar escritas simultâneas nos dois nós.
Qual é a latência típica da sincronização com lsyncd?
É próxima de tempo real, porém depende de I/O, CPU, rede e número de arquivos. Mudanças são agregadas por pequenos atrasos (por exemplo, 2 a 5 segundos) para eficiência. Em picos com muitos arquivos, a sincronização inicial pode demorar mais antes de estabilizar.
Funciona com IPv6 para o VIP?
Funciona se o provedor suportar anúncio do VIP IPv6 e a rede aceitar Neighbor Advertisements, análogos ao ARP do IPv4. Em muitas nuvens, é mais simples usar o floating IP do provedor. Ajuste Keepalived e HAProxy para endereços IPv6 quando necessário.
Posso usar NFS ou storage compartilhado em vez do lsyncd?
Pode, mas adiciona complexidade e possíveis pontos únicos de falha. NFS requer tuning, firewall e testes de lock. O lsyncd é simples para uploads eventuais e diretórios pequenos a médios. Para volumes grandes ou escrita concorrente, avalie storage distribuído.
Quer revisar sua topologia de failover antes de ir a produção?
Envie um esboço da sua rede (IPs, sub‑rede, VIP desejado) e os requisitos de upload. Um olhar externo ajuda a encontrar pontos frágeis e a definir testes de failover realistas.
Converse sobre seu cenárioVeja também
- Guia: checklist técnico para preparar VPS Debian com Docker Compose para aplicações PHP em produção
- Guia prático para dimensionamento de VPS e tuning de PHP‑FPM para lojas Magento/OpenMage com picos sazonais: do sizing ao teste de carga
- guia prático: reconstruir índices no PostgreSQL em produção usando CREATE INDEX CONCURRENTLY e índices parciais (passo a passo seguro)
- Guia prático para implementar retries exponenciais e circuit breaker em integrações entre ERP e marketplaces