Guia prático: como configurar failover ativo-passivo entre duas VPS com Keepalived, HAProxy e lsyncd para uploads sincronizados

Por · Publicado em · 10 min de leitura

Cabo de rede vermelho em primeiro plano com equipamentos de rack de servidores desfocados ao fundo
Infraestrutura de rede e servidores — ideal para ilustrar alta disponibilidade e failover Foto: blickpixel / Pixabay

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ário

Veja também