Voltar ao blog

Configuração de proxy em Ruby com Net::HTTP e Faraday: guia completo para Rails e scripts autônomos

Como configurar corretamente um proxy em projetos Ruby usando Net::HTTP e Faraday - com exemplos para Rails e scripts autônomos, rotação de IP e contorno de bloqueios.

📅13 de agosto de 2026
```html

Se você está escrevendo um parser, integrando uma API externa ou automatizando a coleta de dados em Ruby — cedo ou tarde você encontrará bloqueios por IP. Wildberries, Ozon, Instagram e dezenas de outros serviços cortam solicitações de um único endereço já após algumas centenas de acessos. A solução é uma — proxies. Neste artigo, vamos explorar como conectar proxies a um projeto Ruby através do padrão Net::HTTP e do popular cliente HTTP Faraday, configurar a rotação de IP e tratar erros corretamente — tanto em uma aplicação Rails quanto em scripts simples.

Por que um desenvolvedor Ruby precisa de proxies: cenários principais

Ruby é amplamente utilizado para tarefas onde proxies são indispensáveis. Antes de passar para o código, é importante entender em quais situações eles são necessários — isso ajudará a escolher o tipo e a arquitetura corretos da solução.

Parsing e coleta de dados. Este é o cenário mais comum. Você escreve um script em Ruby que navega pelas páginas do Wildberries, Ozon ou Avito, coletando preços e características dos produtos. Sem proxies, tal script será bloqueado por IP em poucos minutos. Os sites detectam centenas de solicitações de um único endereço e ativam automaticamente a proteção — captcha, ban temporário ou recusa total de serviço.

Integração com APIs dependentes de geolocalização. Alguns serviços externos retornam conteúdo diferente dependendo do país da solicitação. Se sua aplicação Rails faz chamadas a tal API, proxies permitem simular solicitações da região desejada. Por exemplo, verificar os resultados dos motores de busca para diferentes países ou obter preços relevantes para um mercado específico.

Testes e QA. Desenvolvedores usam proxies para testar o comportamento da aplicação em solicitações de diferentes endereços IP e países. Isso é especialmente relevante para serviços com geobloqueio ou limitação de taxa por IP.

Automação de marketing. Scripts Ruby são frequentemente usados para monitorar campanhas publicitárias, verificar posições em resultados de busca ou rastrear a atividade de concorrentes. Aqui, proxies são necessários para distribuir a carga e contornar restrições.

Trabalho com várias contas. Se seu script gerencia várias contas em uma única plataforma, cada conta deve operar através de um IP separado — caso contrário, a plataforma facilmente detectará a conexão e bloqueará tudo de uma vez.

Qual tipo de proxy escolher para tarefas em Ruby

Nem todos os proxies são igualmente adequados para diferentes tarefas. A escolha do tipo impacta diretamente no sucesso do seu script. Vamos analisar as principais opções em relação ao desenvolvimento Ruby.

Tipo de proxy Melhores tarefas em Ruby Velocidade Contorno de proteções
Proxies de data center Parsing sem proteção rigorosa, solicitações de API, testes Alta Média
Proxies residenciais Parsing de sites protegidos, trabalho com redes sociais, marketplaces Média Alta
Proxies móveis Facebook, Instagram, TikTok API, trabalho com contas Média Máxima

Proxies de data center — a opção mais rápida e barata. Adequados para parsing de sites sem proteção agressiva, solicitações de API em massa e testes de carga. No entanto, grandes plataformas (Facebook, Google, Cloudflare) facilmente os reconhecem pelo ASN do data center.

Proxies residenciais utilizam IPs de usuários domésticos reais. Para scripts Ruby que fazem parsing do Wildberries, Ozon ou trabalham com sites protegidos — esta é a escolha ideal. Os sites veem um usuário comum, e não um servidor.

Proxies móveis operam através de IPs de operadores móveis (4G/5G). Esses são os endereços mais confiáveis do ponto de vista das plataformas — um IP móvel pode ser utilizado por centenas de usuários reais simultaneamente, portanto, bloqueios são extremamente raros. Se seu script Ruby trabalha com redes sociais ou plataformas publicitárias — proxies móveis reduzirão o risco de bloqueios ao mínimo.

Proxies em Net::HTTP: configuração básica

Net::HTTP — a biblioteca padrão do Ruby para solicitações HTTP, incluída na distribuição padrão da linguagem. Ela suporta proxies "out of the box" através de um método especial Net::HTTP::Proxy.

A maneira mais simples é criar uma classe de proxy e usá-la em vez do Net::HTTP normal:

require 'net/http'
require 'uri'

# Dados do proxy
proxy_host = 'proxy.example.com'
proxy_port = 8080

# Criando a classe de proxy
proxy_class = Net::HTTP::Proxy(proxy_host, proxy_port)

# Executando a solicitação através do proxy
uri = URI('https://httpbin.org/ip')

proxy_class.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
  request = Net::HTTP::Get.new(uri)
  response = http.request(request)
  puts response.body
end

O método Net::HTTP::Proxy aceita quatro parâmetros: host do proxy, porta, nome de usuário e senha. Os dois primeiros são obrigatórios, os últimos dois são opcionais para proxies sem autenticação.

Uma alternativa é passar os parâmetros do proxy diretamente para o método Net::HTTP.new:

require 'net/http'

uri = URI('https://httpbin.org/ip')

http = Net::HTTP.new(
  uri.host,
  uri.port,
  'proxy.example.com',  # proxy_addr
  8080,                  # proxy_port
  nil,                   # proxy_user (nil se sem autenticação)
  nil                    # proxy_pass
)

http.use_ssl = true

response = http.get(uri.path)
puts response.body

Essa abordagem é conveniente quando você precisa reutilizar o mesmo objeto HTTP para várias solicitações a um único host. Observe que os parâmetros do proxy são passados como o terceiro e quarto argumento, e não através de um método separado.

Autenticação e HTTPS através do Net::HTTP

A maioria dos proxies comerciais requer autenticação — login e senha. Além disso, ao trabalhar com sites HTTPS, uma configuração adicional de SSL é necessária. Vamos analisar ambos os casos.

Proxies com login e senha:

require 'net/http'
require 'uri'

proxy_host = 'proxy.example.com'
proxy_port = 8080
proxy_user = 'your_username'
proxy_pass = 'your_password'

# Criando a classe de proxy com autenticação
proxy_class = Net::HTTP::Proxy(proxy_host, proxy_port, proxy_user, proxy_pass)

uri = URI('https://httpbin.org/ip')

proxy_class.start(uri.host, uri.port, use_ssl: true) do |http|
  # Desativando a verificação de SSL (apenas para testes!)
  # http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  
  request = Net::HTTP::Get.new(uri)
  request['User-Agent'] = 'Mozilla/5.0 (compatible; MyBot/1.0)'
  
  response = http.request(request)
  puts "IP: #{response.body}"
  puts "Status: #{response.code}"
end

Um ponto importante: ao usar proxies HTTPS (túnel através do CONNECT) Net::HTTP estabelece automaticamente uma conexão SSL com o servidor de destino através do túnel proxy. Isso funciona corretamente para a maioria dos servidores proxy.

Configuração através de variáveis de ambiente. Uma boa prática é não hardcodar os dados do proxy no código, mas lê-los a partir de variáveis de ambiente:

require 'net/http'
require 'uri'

# Lendo as configurações do proxy do ENV
proxy_uri = URI(ENV.fetch('HTTP_PROXY', 'http://proxy.example.com:8080'))

proxy_class = Net::HTTP::Proxy(
  proxy_uri.host,
  proxy_uri.port,
  proxy_uri.user,
  proxy_uri.password
)

target_uri = URI('https://httpbin.org/ip')

proxy_class.start(target_uri.host, target_uri.port, use_ssl: true) do |http|
  response = http.get(target_uri.path)
  puts response.body
end

A variável de ambiente pode ser definida no formato HTTP_PROXY=http://user:[email protected]:8080. Essa abordagem permite mudar o proxy sem alterar o código — basta atualizar a variável no arquivo .env ou nas configurações do servidor.

Conectando proxies através do Faraday

Faraday é um dos clientes HTTP mais populares no ecossistema Ruby. Ele é usado em muitas aplicações Rails devido à sua abordagem conveniente de middleware e suporte a diferentes adaptadores (Net::HTTP, HTTParty, Typhoeus e outros). A configuração de proxies no Faraday é um pouco diferente dependendo do adaptador utilizado.

Configuração básica de proxies no Faraday:

require 'faraday'

# Criando uma conexão Faraday com proxy
conn = Faraday.new(url: 'https://httpbin.org') do |faraday|
  faraday.proxy = {
    uri: 'http://proxy.example.com:8080',
    user: 'your_username',
    password: 'your_password'
  }
  
  faraday.headers['User-Agent'] = 'Mozilla/5.0 (compatible; MyBot/1.0)'
  faraday.adapter Faraday.default_adapter
end

response = conn.get('/ip')
puts response.body
puts "Status: #{response.status}"

O parâmetro faraday.proxy aceita um hash com as chaves uri, user e password. Você também pode passar uma string URI diretamente, se o proxy não exigir autenticação.

Faraday com adaptador Net::HTTP e configurações avançadas:

require 'faraday'

conn = Faraday.new(url: 'https://httpbin.org') do |faraday|
  faraday.proxy = 'http://user:[email protected]:8080'
  
  # Configurações de timeout
  faraday.options.timeout = 30
  faraday.options.open_timeout = 10
  
  # Middleware para logging (útil durante a depuração)
  faraday.response :logger
  
  # Retry em caso de erros de conexão
  faraday.request :retry, max: 3, interval: 1
  
  # Adaptador
  faraday.adapter :net_http
end

begin
  response = conn.get('/ip')
  puts response.body
rescue Faraday::ConnectionFailed => e
  puts "Erro de conexão: #{e.message}"
rescue Faraday::TimeoutError => e
  puts "Timeout: #{e.message}"
end

O middleware :retry é especialmente útil ao trabalhar com proxies — se um endereço estiver temporariamente indisponível, o Faraday tentará automaticamente repetir a solicitação. Isso é crítico para o funcionamento confiável do script em produção.

Faraday com adaptador Typhoeus (para solicitações paralelas):

# Gemfile: gem 'typhoeus'
require 'faraday'
require 'typhoeus/adapters/faraday'

conn = Faraday.new(url: 'https://httpbin.org') do |faraday|
  faraday.proxy = 'http://user:[email protected]:8080'
  faraday.adapter :typhoeus
end

# Solicitações paralelas através do proxy
responses = []
conn.in_parallel do
  responses << conn.get('/ip')
  responses << conn.get('/headers')
  responses << conn.get('/user-agent')
end

responses.each { |r| puts r.body }

Rotação de proxies: troca automática de IP

Um único endereço proxy, mesmo residencial, cedo ou tarde encontrará limitações durante um parsing intensivo. A solução é a rotação: troca automática de IP após cada solicitação ou em intervalos determinados. Vamos implementar um simples rotator para scripts Ruby.

Um rotator simples baseado em um array de proxies:

require 'net/http'
require 'uri'

class ProxyRotator
  def initialize(proxies)
    @proxies = proxies
    @index = 0
    @mutex = Mutex.new
  end

  def next_proxy
    @mutex.synchronize do
      proxy = @proxies[@index % @proxies.length]
      @index += 1
      proxy
    end
  end

  def random_proxy
    @proxies.sample
  end
end

# Lista de proxies no formato [host, port, user, pass]
proxies = [
  ['proxy1.example.com', 8080, 'user1', 'pass1'],
  ['proxy2.example.com', 8080, 'user2', 'pass2'],
  ['proxy3.example.com', 8080, 'user3', 'pass3'],
]

rotator = ProxyRotator.new(proxies)

# Fazendo parsing de uma lista de URLs através de diferentes proxies
urls = [
  'https://httpbin.org/ip',
  'https://httpbin.org/headers',
  'https://httpbin.org/user-agent'
]

urls.each do |url|
  proxy = rotator.next_proxy
  proxy_class = Net::HTTP::Proxy(proxy[0], proxy[1], proxy[2], proxy[3])
  
  uri = URI(url)
  
  begin
    proxy_class.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
      http.read_timeout = 15
      response = http.get(uri.path)
      puts "#{url} -> Status: #{response.code}, Proxy: #{proxy[0]}"
    end
  rescue => e
    puts "Erro com o proxy #{proxy[0]}: #{e.message}"
    # Passa automaticamente para o próximo proxy
  end
  
  sleep(rand(0.5..2.0)) # Atraso aleatório entre as solicitações
end

O atraso aleatório entre as solicitações (sleep(rand(0.5..2.0))) é um elemento importante. O padrão de solicitações com intervalos fixos é facilmente detectado por sistemas anti-bot. Atrasos aleatórios imitam o comportamento de um usuário real.

Rotação através do Faraday com middleware:

require 'faraday'

class ProxyMiddleware < Faraday::Middleware
  PROXIES = [
    'http://user1:[email protected]:8080',
    'http://user2:[email protected]:8080',
    'http://user3:[email protected]:8080',
  ].freeze

  def call(env)
    # Escolhendo um proxy aleatório para cada solicitação
    proxy_uri = URI(PROXIES.sample)
    
    env[:request][:proxy] = {
      uri: proxy_uri,
      user: proxy_uri.user,
      password: proxy_uri.password
    }
    
    @app.call(env)
  end
end

# Registrando o middleware
Faraday::Middleware.register_middleware proxy_rotator: ProxyMiddleware

conn = Faraday.new(url: 'https://httpbin.org') do |faraday|
  faraday.use :proxy_rotator
  faraday.adapter :net_http
end

5.times do
  response = conn.get('/ip')
  puts response.body
end

Integração de proxies em uma aplicação Rails

Em uma aplicação Rails, proxies são frequentemente necessários para solicitações HTTP externas: integração com APIs, tarefas de parsing em segundo plano ou webhooks. Vamos explorar alguns padrões práticos.

Padrão 1: Objeto de serviço com Faraday. Criamos uma classe de serviço básica que faz todas as solicitações HTTP externas através de proxies:

# app/services/http_client.rb
class HttpClient
  def self.connection(base_url)
    Faraday.new(url: base_url) do |faraday|
      # Proxies a partir de variáveis de ambiente Rails
      if Rails.env.production? && ENV['PROXY_URL'].present?
        faraday.proxy = ENV['PROXY_URL']
      end
      
      faraday.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
      faraday.options.timeout = 30
      faraday.options.open_timeout = 10
      
      faraday.request :retry, max: 3, interval: 2,
                      exceptions: [Faraday::ConnectionFailed, Faraday::TimeoutError]
      
      faraday.response :raise_error
      faraday.adapter :net_http
    end
  end
end

# Uso em um controlador ou serviço:
# client = HttpClient.connection('https://api.example.com')
# response = client.get('/products', { category: 'electronics' })

Padrão 2: Configuração através de credenciais do Rails. Para armazenar dados do proxy, utilize credenciais criptografadas do Rails:

# config/credentials.yml.enc (editado através de rails credentials:edit)
# proxy:
#   host: proxy.example.com
#   port: 8080
#   username: your_user
#   password: your_pass

# app/services/proxy_service.rb
class ProxyService
  def self.faraday_proxy_config
    creds = Rails.application.credentials.proxy
    return nil unless creds
    
    {
      uri: "http://#{creds[:host]}:#{creds[:port]}",
      user: creds[:username],
      password: creds[:password]
    }
  end
  
  def self.net_http_proxy
    creds = Rails.application.credentials.proxy
    return Net::HTTP::Proxy(nil, nil) unless creds
    
    Net::HTTP::Proxy(
      creds[:host],
      creds[:port],
      creds[:username],
      creds[:password]
    )
  end
end

Padrão 3: Tarefas em segundo plano com Sidekiq. Se o parsing ou as solicitações de API são executadas em trabalhadores em segundo plano, a configuração do proxy permanece a mesma, mas é importante considerar a concorrência:

# app/workers/price_parser_worker.rb
class PriceParserWorker
  include Sidekiq::Worker
  
  sidekiq_options retry: 3, queue: :parsers
  
  def perform(product_url)
    # Criando uma nova conexão para cada trabalhador
    proxy = ProxyService.net_http_proxy
    uri = URI(product_url)
    
    proxy.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
      http.read_timeout = 20
      
      request = Net::HTTP::Get.new(uri)
      request['User-Agent'] = random_user_agent
      
      response = http.request(request)
      
      if response.code == '200'
        parse_and_save(response.body, product_url)
      else
        Rails.logger.warn "Status inesperado #{response.code} para #{product_url}"
      end
    end
  rescue Net::OpenTimeout, Net::ReadTimeout => e
    Rails.logger.error "Timeout para #{product_url}: #{e.message}"
    raise # Sidekiq repetirá a tarefa
  end
  
  private
  
  def random_user_agent
    agents = [
      'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
      'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
      'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
    ]
    agents.sample
  end
  
  def parse_and_save(html, url)
    # Lógica de parsing...
  end
end

Tratamento de erros e timeouts

Trabalhar através de proxies adiciona uma camada adicional que pode gerar erros específicos. Um tratamento de exceções adequado é a diferença entre um script que falha em 5 minutos e um script que funciona por horas sem intervenção.

Principais tipos de erros ao trabalhar com proxies em Ruby:

Exceção Causa O que fazer
Net::OpenTimeout Proxy não responde Trocar proxy, repetir
Net::ReadTimeout Proxy lento ou site não responde Aumentar timeout ou trocar proxy
Errno::ECONNREFUSED Servidor proxy rejeitou a conexão Verificar dados do proxy
OpenSSL::SSL::SSLError Problema com SSL através do proxy Verificar configurações de SSL
HTTP 407 Login/senha do proxy incorretos Verificar credenciais
HTTP 403/429 IP bloqueado pelo site Trocar proxy, adicionar pausa

Tratamento abrangente de erros com troca automática de proxies:

require 'net/http'
require 'uri'

class RobustHttpClient
  MAX_RETRIES = 3
  RETRIABLE_ERRORS = [
    Net::OpenTimeout,
    Net::ReadTimeout,
    Errno::ECONNREFUSED,
    Errno::ECONNRESET,
    OpenSSL::SSL::SSLError
  ].freeze

  def initialize(proxies)
    @proxies = proxies.dup
    @failed_proxies = []
  end

  def get(url, retries: MAX_RETRIES)
    uri = URI(url)
    attempt = 0

    begin
      attempt += 1
      proxy = current_proxy
      proxy_class = Net::HTTP::Proxy(*proxy)

      proxy_class.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
        http.open_timeout = 10
        http.read_timeout = 20

        request = Net::HTTP::Get.new(uri)
        request['User-Agent'] = 'Mozilla/5.0 (compatible; RubyBot/1.0)'

        response = http.request(request)

        case response.code.to_i
        when 200..299
          response
        when 407
          raise "Falha na autenticação do proxy para #{proxy[0]}"
        when 403, 429
          rotate_proxy!
          raise "IP bloqueado (#{response.code}), trocando proxy"
        else
          raise "Status HTTP inesperado: #{response.code}"
        end
      end

    rescue *RETRIABLE_ERRORS => e
      Rails.logger.warn "Erro de conexão (tentativa #{attempt}/#{retries}): #{e.message}"
      rotate_proxy!
      retry if attempt < retries
      raise "Falhou após #{retries} tentativas: #{e.message}"

    rescue RuntimeError => e
      Rails.logger.warn "Erro HTTP (tentativa #{attempt}/#{retries}): #{e.message}"
      retry if attempt < retries
      raise
    end
  end

  private

  def current_proxy
    @proxies.first || raise("Sem proxies disponíveis!")
  end

  def rotate_proxy!
    failed = @proxies.shift
    @failed_proxies << failed
    Rails.logger.info "Proxy trocado. Restantes: #{@proxies.length}"
  end
end

Proxies SOCKS5 em Ruby: configuração através do socksify

O padrão Net::HTTP não suporta SOCKS5 nativamente — apenas proxies HTTP/HTTPS. Para trabalhar com SOCKS5, é necessária uma biblioteca adicional. A opção mais popular é a gem socksify.

Por que SOCKS5 pode ser preferível a proxies HTTP? O protocolo SOCKS5 opera em um nível mais baixo — ele proxy qualquer tráfego TCP, e não apenas HTTP. Além disso, SOCKS5 suporta autenticação e transmite menos metadados sobre a solicitação, tornando-o menos visível para sistemas de detecção de bots.

# Gemfile
# gem 'socksify'

require 'socksify'
require 'socksify/http'
require 'net/http'
require 'uri'

# Configuração global do proxy SOCKS5
TCPSocket::socks_server = 'proxy.example.com'
TCPSocket::socks_port = 1080

# Opcional: autenticação (SOCKS5 username/password)
# TCPSocket::socks_username = 'your_user'
# TCPSocket::socks_password = 'your_pass'

# Agora todas as solicitações Net::HTTP vão através do SOCKS5
uri = URI('https://httpbin.org/ip')
response = Net::HTTP.get_response(uri)
puts response.body

Observe que ao usar socksify, a configuração é aplicada globalmente a todas as conexões TCP no processo. Se você precisar de uma configuração mais flexível — use Net::HTTP.SOCKSProxy da mesma gem:

require 'socksify/http'

# Criando uma classe de proxy SOCKS5 (semelhante ao Net::HTTP::Proxy para HTTP)
socks_proxy = Net::HTTP.SOCKSProxy('proxy.example.com', 1080)

uri = URI('https://httpbin.org/ip')

socks_proxy.start(uri.host, uri.port, use_ssl: true) do |http|
  response = http.get(uri.path)
  puts response.body
end

Para Faraday com SOCKS5, será necessário um adaptador que suporte esse protocolo. Uma boa opção é faraday-net_http em conjunto com socksify, ou usar o adaptador baseado em curl faraday-typhoeus, que suporta nativamente SOCKS5 através do libcurl.

💡 Dica sobre escolha de protocolo

Para a maioria das tarefas de parsing e trabalho com APIs, proxies HTTP/HTTPS são suficientes — eles são mais fáceis de configurar e suportados nativamente. SOCKS5 deve ser usado quando você precisa proxy não apenas tráfego HTTP, ou quando proxies HTTP são facilmente detectados pelo serviço de destino. Proxies móveis e residenciais estão disponíveis em ambos os protocolos.

Conclusão e recomendações

Configurar proxies em Ruby não requer bibliotecas complexas — o padrão Net::HTTP suporta proxies HTTP "out of the box", e o Faraday torna a integração ainda mais conveniente devido à sua arquitetura de middleware. Principais conclusões deste guia:

  • Para Net::HTTP, use Net::HTTP::Proxy — este é um método embutido e confiável.
  • Para Faraday, o parâmetro faraday.proxy aceita uma string URI ou um hash com credenciais.
  • Armazene dados do proxy em variáveis de ambiente ou credenciais do Rails — não hardcode no código.
  • Implemente rotação de proxies e tratamento de erros para um funcionamento confiável em produção.
  • Adicione atrasos aleatórios e rotação de User-Agent para imitar o comportamento humano.
  • Para SOCKS5, use a gem socksify.

A escolha do tipo de proxy depende da tarefa. Se você está escrevendo um parser para Wildberries ou Ozon — proxies residenciais proporcionarão o melhor equilíbrio entre velocidade e contorno de proteções: IPs reais de usuários domésticos raramente entram em listas de bloqueio. Para tarefas de alta carga com um grande volume de solicitações a fontes menos protegidas, proxies de data center são mais rápidos e mais baratos por solicitação. Se seu script Ruby trabalha com redes sociais ou APIs publicitárias — considere proxies móveis: seus endereços IP têm o nível máximo de confiança na maioria das plataformas.

```