O Baileys conecta ao WhatsApp por WebSocket. Para rotear essa conexão por um proxy, você passa um agente customizado na criação do socket — e é isso que faz cada número sair por um endereço próprio em vez do IP da VPS.
Por que isso importa
Um servidor com dez instâncias de Baileys tem, por padrão, dez números saindo pelo mesmo endereço IP — o da máquina. Se aquele endereço apresentar problema, todos os dez são afetados ao mesmo tempo.
Além disso, o IP de um provedor de nuvem pertence a um bloco compartilhado com centenas de outros projetos, cujo histórico você não controla.
Instalação
npm install socks-proxy-agent
Para proxy HTTP em vez de SOCKS5:
npm install https-proxy-agent
Configuração básica com SOCKS5
import makeWASocket from '@whiskeysockets/baileys'
import { SocksProxyAgent } from 'socks-proxy-agent'
const proxyUrl = 'socks5://usuario:[email protected]:1080'
const agent = new SocksProxyAgent(proxyUrl)
const sock = makeWASocket({
auth: state,
agent, // conexão principal (WebSocket)
fetchAgent: agent, // download de mídia
printQRInTerminal: true,
})
Repare nos dois campos. O agent roteia a conexão principal; o fetchAgent roteia o download de mídia. Definir só o primeiro deixa o tráfego de mídia saindo pelo IP da máquina — uma inconsistência que passa despercebida com facilidade.
Um proxy por instância
Encapsule a criação do socket para que cada número receba seu próprio proxy:
import makeWASocket, { useMultiFileAuthState } from '@whiskeysockets/baileys'
import { SocksProxyAgent } from 'socks-proxy-agent'
const instances = [
{ name: 'cliente-a', proxy: 'socks5://user_a:[email protected]:1080' },
{ name: 'cliente-b', proxy: 'socks5://user_b:[email protected]:1080' },
]
async function start({ name, proxy }) {
const { state, saveCreds } = await useMultiFileAuthState(`./auth/${name}`)
const agent = new SocksProxyAgent(proxy)
const sock = makeWASocket({
auth: state,
agent,
fetchAgent: agent,
printQRInTerminal: true,
})
sock.ev.on('creds.update', saveCreds)
sock.ev.on('connection.update', ({ connection, lastDisconnect }) => {
if (connection === 'close') {
const status = lastDisconnect?.error?.output?.statusCode
console.log(`[${name}] desconectado (${status}) — reconectando`)
// recria o socket, passando o mesmo proxy
setTimeout(() => start({ name, proxy }), 5000)
}
if (connection === 'open') {
console.log(`[${name}] conectado`)
}
})
return sock
}
for (const instance of instances) {
await start(instance)
}
O ponto importante está no tratamento de reconexão: o agente é definido na criação do socket, então recriar o socket sem passar o proxy de novo faz o número voltar a sair pelo IP da máquina — silenciosamente.
Senha com caractere especial
Se a senha contém @, :, / ou #, codifique antes de montar a URL:
const user = encodeURIComponent('seu-usuario')
const pass = encodeURIComponent('sua@senha')
const proxyUrl = `socks5://${user}:${pass}@p1.exemplo.com:1080`
O @ é o caso crítico: ele separa credencial de host na estrutura da URL, então uma senha com @ quebra a string sem codificação.
Valide antes de conectar
Confirme a saída antes de gerar o QR Code:
import { SocksProxyAgent } from 'socks-proxy-agent'
import fetch from 'node-fetch'
const agent = new SocksProxyAgent('socks5://usuario:[email protected]:1080')
const res = await fetch('https://ipinfo.io/json', { agent })
console.log(await res.json())
// esperado: o IP contratado, country "BR"
Se o retorno mostrar o IP da VPS, o agente não está sendo aplicado — não faz sentido conectar o número ainda.
Problemas comuns
ECONNREFUSED ao criar o socket — porta errada. Confirme que você usou a porta do SOCKS5.
Erro de autenticação no proxy — senha com caractere especial não codificado, ou credencial com espaço extra.
Conecta e desconecta em loop — pode ser sessão corrompida. Apague a pasta de autenticação daquela instância e reconecte. Se persistir, verifique a versão do Baileys.
Mídia não baixa, mensagens funcionam — você definiu agent mas esqueceu fetchAgent.
Todas as instâncias com o mesmo IP — o proxy foi definido globalmente, não por instância. Revise a função de criação do socket.
Limites do que o proxy resolve
O proxy controla a origem da conexão. Ele não controla as políticas do WhatsApp, limites de envio, qualidade do número ou reclamação de destinatário.
Número bloqueado por padrão de envio é problema de operação, não de rede — e trocar de IP não corrige isso.
Se você usa a Evolution API em vez de Baileys direto, veja o guia da Evolution API.