Дешевий проксі
Інтеграції
Ruby proxy integration: Net::HTTP, Faraday, and rotation

Ruby Proxy Integration

Route Ruby requests through a proxy with Net::HTTP, Faraday, HTTParty, and Typhoeus. Tested code, rotation, SOCKS5, error fixes, and Proxy-Cheap proxies.
Отримати проксі для Ruby proxy integration: Net::HTTP, Faraday, and rotation
Ruby proxy integration: Net::HTTP, Faraday, and rotation
What is a proxy in Ruby?
A proxy in Ruby is a server your HTTP client routes through instead of connecting directly, so the target site sees the proxy's IP, not yours. Ruby has no single proxy switch, so you configure it on whichever client makes the request, whether that's Net::HTTP or a gem like Faraday or Typhoeus. Pairing it with a Proxy-Cheap proxy keeps scraping scripts running reliably at scale.

Key takeaways

  • Ruby has no single proxy switch. You configure the proxy on whichever HTTP client makes the request: Net::HTTP, open-uri, HTTParty, Faraday, or Typhoeus.
  • Net::HTTP is built in. Pass the proxy as arguments 3 to 6 of Net::HTTP.new (host, port, user, pass), and set use_ssl = true for HTTPS targets.
  • Route requests through the Proxy-Cheap hub (thehub.proxy-cheap.com:8080) and open a fresh connection per request to rotate exit IPs.
  • SOCKS5 is not built into Net::HTTP. Use the socksify gem or a libcurl-backed client like Typhoeus, and match the Proxy-Cheap product to the workload.

What is a proxy in Ruby?

A proxy is an intermediary server that forwards your HTTP requests. Instead of connecting straight to a target site, your Ruby code sends the request to the proxy, the proxy forwards it from its own IP address, and the response returns the same way. The target site sees the proxy's IP, not the IP of the machine running your script.

Ruby has no global proxy setting the way a desktop browser does. You configure the proxy on the HTTP client that makes the request. Every mainstream Ruby HTTP client accepts proxy settings: the built-in Net::HTTP and open-uri, plus popular gems like HTTParty, Faraday, and Typhoeus. The option names differ between them, but the inputs are always the same four values: proxy host, port, username, and password.

That is the whole idea behind Ruby proxy integration. You take the credentials your proxy provider gives you and pass them to your HTTP client of choice. The rest of this guide shows the exact syntax for each client, then adds rotation, SOCKS5, and the error fixes that the thin tutorials leave out.

What is a Ruby proxy used for?

A Ruby proxy is used wherever a script needs to send many requests, or requests from a specific location, without every one of them originating from a single server IP. The most common applications:

  • Public-web data collection at scale. Read product names, prices, ratings, and availability from catalog pages into clean Ruby objects.
  • Price and market intelligence. Track public competitor pricing and product listings across markets over time.
  • SEO and SERP research. Query public search results from multiple geographies to monitor rankings and localized results.
  • Ad verification. Review publicly served ads across geo-specific markets for compliance and quality assurance.
  • Localization and QA testing. Test how applications and content render for users in different regions.
  • AI training and RAG pipelines. Gather publicly available data at scale to build retrieval corpora and training sets.

The common thread is volume and location. A single IP sending hundreds of requests a minute gets rate-limited fast, and it always sees the same regional content. A pool of proxy IPs keeps response success rates stable across long jobs and returns the data a real user in the target market would see.

Ruby HTTP clients that support proxies

Ruby gives you several HTTP clients, and each one attaches the proxy in a slightly different place. Picking the right client is the first decision in any integration.

Comparison table of five Ruby HTTP clients (Net::HTTP, open-uri, HTTParty, Faraday, Typhoeus) showing what each is best for and the exact proxy option each one uses.

Every mainstream Ruby HTTP client accepts a proxy. The option name changes, but the four inputs (host, port, user, pass) stay the same.

  • Net::HTTP ships with Ruby, needs no gem, and is the right default for most scripts. The proxy goes in the constructor.
  • open-uri wraps Net::HTTP for one-line page fetches. Good for quick reads, less so for fine control.
  • HTTParty is a friendly wrapper for REST-style calls. It exposes four discrete proxy options.
  • Faraday is the middleware-based client used by many Ruby SDKs. Its default adapter in the 2.x line is Net::HTTP, and it takes the proxy as a URL.
  • Typhoeus rides on libcurl, which unlocks true parallel requests and native SOCKS5 support.

Mechanize, a scraping-focused client that also wraps Net::HTTP, rounds out the list with agent.set_proxy(host, port, user, pass). If you are unsure, start with Net::HTTP and move to Faraday or Typhoeus when you need middleware or concurrency.

Installing the Ruby HTTP client gems

You need Ruby installed first. The current stable release is Ruby 4.0.5, and everything in this guide runs on Ruby 3.0 or newer. Check your version:

ruby --version

Net::HTTP and open-uri are part of Ruby's standard library, so they need no installation. You just require them. The other clients are gems. Install the ones you plan to use:

gem install httparty faraday typhoeus mechanize socksify

For a project, add them to a Gemfile and let Bundler lock the versions:

# Gemfile
source 'https://rubygems.org'
 
gem 'httparty', '~> 0.24'
gem 'faraday',  '~> 2.14'
gem 'typhoeus', '~> 1.6'   # needs libcurl on the system
gem 'socksify', '~> 1.8'   # SOCKS5 support for Net::HTTP

Then run bundle install. One note on Typhoeus: it binds to the system libcurl library, which is present by default on most Linux and macOS machines. On Windows you may need to install a libcurl build separately.

Quickstart: your first proxied request in Ruby

Here is the smallest working example. It uses the built-in Net::HTTP and the Proxy-Cheap rotating residential hub to fetch your outbound IP, which is the quickest way to prove the proxy is live.

require 'net/http'
require 'uri'
 
uri = URI('https://httpbin.org/ip')
 
# Arguments 3 to 6 of Net::HTTP.new are the proxy: host, port, user, pass.
http = Net::HTTP.new(uri.host, uri.port,
                     'thehub.proxy-cheap.com', 8080,
                     '<your-proxycheap-username>', '<your-proxycheap-password>')
 
http.use_ssl = (uri.scheme == 'https')   # required for HTTPS through a proxy
 
response = http.get(uri.request_uri)
puts response.code    # 200 with valid credentials
puts response.body    # {"origin": "the proxy exit IP"}

With real credentials this prints 200 and a JSON body showing the proxy exit IP instead of your own. With placeholder credentials the gateway answers 407 Proxy Authentication Required, which itself confirms your request reached the proxy and the configuration is correct. That 407 is the signal to swap in your dashboard credentials.

The one line people miss is http.use_ssl = true. On a proxied Net::HTTP object, the SSL flag is not inferred from the URL. Without it, Ruby never opens the secure tunnel to an HTTPS site and the request fails. Set it from the URL scheme every time.

Why you need a proxy for Ruby web scraping

A direct connection from one server IP is fine for a handful of requests. It stops being fine the moment you scale to a real workload, which is why serious Ruby scraping runs through a residential proxy network. Three concrete reasons:

  1. Reliable connectivity and stable session quality. Many sites throttle repeated requests from a single IP. Spreading requests across a pool of IPs keeps response success rates high across long crawls.
  2. Accurate geo-specific data. Prices, listings, and search results vary by country and city. Routing through an IP in the target market is the only way to capture what a user there actually sees.
  3. Compliance with site terms and regional requirements. Public-web data collection at scale should respect rate limits and regional rules. Country and city targeting lets you stay within those boundaries while still gathering the data you need.

Proxy-Cheap offers four product lines that map cleanly onto Ruby workloads.

Card layout matching four Proxy-Cheap product types to Ruby workloads: rotating residential, static residential ISP, ISP, and datacenter proxies.

Pick the product by the shape of the target site. The links below match the cards above.

  • Rotating residential proxies for high-volume scraping and geo-specific data. 155M+ IPs across 180+ countries, with a new exit IP per request or a sticky session.
  • Static residential (ISP) proxies for logins and account-bound sessions where the same IP must persist. ISP-assigned and high in legitimacy.
  • ISP proxies for long-lived sessions with flexible authentication. Static and rotating options, HTTP and SOCKS5, username and password or IP allowlist.
  • Datacenter proxies for high-throughput crawls of public catalogs and APIs. Fast and predictable per-IP pricing.

For most Ruby projects the answer is one of these four, chosen by the target site rather than the budget.

How to set up a proxy in Ruby

Every request follows the same path: your Ruby client sends the request to the Proxy-Cheap gateway, the gateway forwards it through an exit IP, and the response returns to your code.

Diagram of a Ruby request flowing from the script through the Proxy-Cheap gateway to a target website and back as response.body, with credentials attached at the gateway.

One Proxy-Cheap endpoint sits between your Ruby code and the target site. The same request and response travel through it.

Before the code, a quick note on the Proxy-Cheap endpoint format, because it differs by product:

  • Rotating residential uses a single shared hub: thehub.proxy-cheap.com on port 8080. You choose the country in the dashboard credential generator, so there is no separate US or EU gateway. Each connection through the hub gets a new exit IP.
  • Static residential, ISP, and datacenter assign a unique IP and port to each proxy you order. You copy the exact host and port from the Proxy-Cheap dashboard's Setup Credentials panel.

Below is the same request through each client. Keep your credentials out of source control by reading them from environment variables.

Net::HTTP (built in). The full form with timeouts and SSL:

require 'net/http'
require 'uri'
 
uri  = URI('https://httpbin.org/ip')
user = ENV.fetch('PROXY_USER')
pass = ENV.fetch('PROXY_PASS')
 
http = Net::HTTP.new(uri.host, uri.port, 'thehub.proxy-cheap.com', 8080, user, pass)
http.use_ssl      = (uri.scheme == 'https')
http.open_timeout = 10
http.read_timeout = 20
 
response = http.get(uri.request_uri)
puts response.code

open-uri (built in). A one-line read with basic proxy authentication:

require 'open-uri'
 
body = URI.open('https://httpbin.org/ip',
  proxy_http_basic_authentication: [
    'http://thehub.proxy-cheap.com:8080',
    ENV.fetch('PROXY_USER'),
    ENV.fetch('PROXY_PASS')
  ]).read
 
puts body

Pass either :proxy or :proxy_http_basic_authentication, never both. Passing both raises ArgumentError: multiple proxy options specified.

HTTParty. Four discrete options, credentials in their own fields:

require 'httparty'
 
response = HTTParty.get('https://httpbin.org/ip',
  http_proxyaddr: 'thehub.proxy-cheap.com',
  http_proxyport: 8080,
  http_proxyuser: ENV.fetch('PROXY_USER'),
  http_proxypass: ENV.fetch('PROXY_PASS'))
 
puts response.code

Faraday. Faraday takes the proxy as a URL, with the credentials in the userinfo:

require 'faraday'
require 'cgi'
 
user = CGI.escape(ENV.fetch('PROXY_USER'))   # percent-encode in case of special characters
pass = CGI.escape(ENV.fetch('PROXY_PASS'))
 
conn = Faraday.new(
  url:   'https://httpbin.org',
  proxy: "http://#{user}:#{pass}@thehub.proxy-cheap.com:8080"
)
 
response = conn.get('/ip')
puts response.status

If you prefer to keep the credentials out of the URL, Faraday also accepts a hash with :uri, :user, and :password:

conn = Faraday.new(url: 'https://httpbin.org', proxy: {
  uri:      'http://thehub.proxy-cheap.com:8080',
  user:     ENV.fetch('PROXY_USER'),
  password: ENV.fetch('PROXY_PASS')
})

Proxy-Cheap delivers credentials in standard host:port plus username:password form, which maps directly onto every example above. For a full walkthrough of generating them, see the step-by-step guide to residential proxies.

Rotating proxies in Ruby

You get rotation in two different ways, depending on the product:

  • Rotating residential. Rotation happens at the hub. Every connection through thehub.proxy-cheap.com:8080 gets a new exit IP, so one entry in your config is enough.
  • Static residential, ISP, or datacenter. Each proxy is a fixed IP. To rotate, you keep a list and cycle through it in code.

Here is a round-robin over a pool that works for both cases. The key detail is that a fresh Net::HTTP object opens a new TCP connection, and a new connection is what triggers a new exit IP on a rotating gateway:

require 'net/http'
require 'uri'
 
# For static residential, ISP, or datacenter proxies, list the host:port pairs
# from your dashboard. For the rotating hub, a single entry is enough.
PROXIES = [
  ['thehub.proxy-cheap.com', 8080]
]
USER = ENV.fetch('PROXY_USER')
PASS = ENV.fetch('PROXY_PASS')
 
def fetch(url, proxy_host, proxy_port)
  uri  = URI(url)
  # A new object per call means a new TCP connection, and a new exit IP.
  http = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port, USER, PASS)
  http.use_ssl      = (uri.scheme == 'https')
  http.open_timeout = 10
  http.read_timeout = 20
  http.get(uri.request_uri)
end
 
10.times do |i|
  host, port = PROXIES[i % PROXIES.size]   # round-robin; use PROXIES.sample for random
  response = fetch('https://httpbin.org/ip', host, port)
  puts "[#{i}] via #{host}: #{response.code}"
end

Rotation logic lives in your code, not inside the library. That matters for one common surprise: if you wrap many requests in a single persistent connection, a rotating gateway can hand you the same IP each time, because the socket is reused. Open a fresh connection when you want a fresh IP.

When to use rotating versus static depends on the workload. Rotating residential is the default for high-volume scraping, where a new IP per request keeps success rates stable. Static residential holds one IP for hours, which suits account-bound sessions and stateful dashboards. For a deeper comparison, read static vs rotating proxies. The pattern here mirrors other languages too, as in how to rotate proxies in Python with Requests and AIOHTTP.

Advanced: SOCKS5 and parallel requests in Ruby

Two capabilities separate a basic integration from a production one: SOCKS5 support and concurrency.

SOCKS5 with socksify. Net::HTTP speaks HTTP proxies only, so SOCKS5 needs help. The socksify gem adds it. Copy the SOCKS host and port from your dashboard, since the :8080 gateway is for HTTP:

require 'socksify/http'
require 'uri'
 
uri = URI('https://httpbin.org/ip')
 
Net::HTTP.socks_proxy('socks-host-from-dashboard', 1080,
                      username: ENV.fetch('PROXY_USER'),
                      password: ENV.fetch('PROXY_PASS'))
        .start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
  response = http.get(uri.request_uri)
  puts response.body
end

socksify resolves the hostname through the proxy rather than locally, which is the behavior you want for accurate geo-specific results. If you want to learn how the protocol differs from HTTP, see what is a SOCKS proxy.

SOCKS5 with Typhoeus. Because Typhoeus rides libcurl, it supports SOCKS5 directly. One trap: proxytype must be a symbol. Passing the string 'socks5' is silently ignored:

require 'typhoeus'
 
response = Typhoeus.get('https://httpbin.org/ip',
  proxy:        'socks-host-from-dashboard:1080',
  proxytype:    :socks5,   # a symbol, not the string 'socks5'
  proxyuserpwd: "#{ENV.fetch('PROXY_USER')}:#{ENV.fetch('PROXY_PASS')}")
 
puts response.code

Parallel requests with Typhoeus Hydra. For throughput, Typhoeus runs many requests at once through Hydra, each carrying the proxy:

require 'typhoeus'
 
hydra = Typhoeus::Hydra.new(max_concurrency: 5)
creds = "#{ENV.fetch('PROXY_USER')}:#{ENV.fetch('PROXY_PASS')}"
 
urls = ['https://httpbin.org/ip'] * 10
requests = urls.map do |url|
  req = Typhoeus::Request.new(url,
    proxy:        'http://thehub.proxy-cheap.com:8080',
    proxyuserpwd: creds,
    timeout:      20)
  hydra.queue(req)
  req
end
 
hydra.run   # runs the whole batch in parallel
 
requests.each { |r| puts r.response.code }

Hydra caps concurrency at max_concurrency and runs the batch together, which is far faster than looping one request at a time when you have hundreds of URLs.

Common Ruby proxy errors and how to fix them

Most Ruby proxy failures fall into a handful of buckets. Each has a simple fix.

1. The proxy is ignored and the request goes direct. You called a class method like Net::HTTP.get(uri). Those shortcuts skip proxy handling entirely, including the http_proxy environment variable. Build an instance instead: http = Net::HTTP.new(host, port, proxy_host, proxy_port); http.get(path).

2. The proxy arguments land in the wrong slots. The signature is Net::HTTP.new(address, port, p_addr, p_port, p_user, p_pass). The target host and port are arguments 1 and 2, the proxy host and port are 3 and 4, and the credentials are 5 and 6. Passing the proxy host as argument 1 is the most common mistake.

3. HTTPS fails with an SSL error through the proxy. On a proxied object, use_ssl is not set from the URL. Add http.use_ssl = (uri.scheme == 'https') so Ruby opens the secure tunnel and verifies the certificate. Do not disable verification to silence the error; if the certificate store is missing, point SSL_CERT_FILE at a valid CA bundle instead.

4. 407 Proxy Authentication Required. The credentials are missing or in the wrong place. For Net::HTTP they are arguments 5 and 6, for HTTParty they are http_proxyuser and http_proxypass, and for Faraday they go in the proxy URL. A 407 against the gateway with correct credentials means the account or IP allowlist needs attention.

5. Still 407 even though the credentials are correct. The password contains a reserved character such as @, :, or #, and it is breaking the proxy URL. Percent-encode each credential with CGI.escape before putting it in a URL, or pass the credentials as separate arguments (Net::HTTP, HTTParty) to skip URL parsing entirely.

6. Faraday ignores the proxy. Set the proxy at connection creation in Faraday.new, not per request. Faraday also reads http_proxy and https_proxy from the environment, so an env var can override an explicit setting. Pass proxy: nil to ignore the environment, and pin a current Faraday 2.x version.

7. A rotating proxy returns the same IP every time. A persistent or reused connection keeps the same exit IP because the gateway assigns the IP per TCP connection. Open a fresh Net::HTTP object per request, or send Connection: close, so each request gets a new connection and a new IP.

8. SOCKS5 will not work with Net::HTTP. There is no native SOCKS support in the standard library. Use the socksify gem or a libcurl-backed client like Typhoeus, as shown above. For hostname privacy and accurate geo results, let the proxy resolve DNS (the socks5h behavior), which socksify does by default.

Best practices for Ruby proxy integration

A few habits keep a Ruby proxy integration reliable as it grows:

  • Read credentials from environment variables, never hardcode them. ENV.fetch('PROXY_USER') raises early if the value is missing, which is better than a silent 407 later.
  • Set timeouts and retries. Give every request an open_timeout and read_timeout, and wrap it in a small retry loop that rescues Net::OpenTimeout, Net::ReadTimeout, and Errno::ECONNREFUSED with exponential backoff.
  • Match the product to the workload. Rotating residential for high-volume and geo-specific jobs, static residential or ISP for account-bound sessions, datacenter for high-throughput public targets.
  • Verify the exit IP. A quick call to https://httpbin.org/ip or https://api.ipify.org confirms the proxy is live before you run a large job.
  • Pick the client for the job. Net::HTTP for simple scripts, Faraday for middleware and SDKs, Typhoeus for parallel requests and SOCKS5. All of them take the same four inputs.

Get the client and the product right, and Ruby proxy integration comes down to four values passed to one HTTP call. Everything after that (rotation, SOCKS5, concurrency) builds on the same foundation.

Поширені запитання

Instance-based Net::HTTP and open-uri honor the lowercase http_proxy variable through the :ENV default, and they respect no_proxy for exclusions. Class shortcuts like Net::HTTP.get do not. When you need predictable behavior, pass the proxy explicitly rather than trusting the environment.

No. Net::HTTP and open-uri are in Ruby's standard library and support proxies out of the box, so a basic integration needs zero gems. You only install a gem (HTTParty, Faraday, Typhoeus, socksify) when you want its specific features, such as concurrency or SOCKS5.

For most scripts, the built-in Net::HTTP is enough. Choose Faraday when you already use it for API calls or want middleware, HTTParty for concise REST requests, and Typhoeus when you need parallel requests or SOCKS5. They all accept the same host, port, user, and password.

Yes. Pass proxy: "http://user:pass@host:port" to Faraday.new, or use the hash form with :uri, :user, and :password. Set the proxy at connection creation, not per request, and percent-encode credentials that contain special characters.

Not natively. Net::HTTP handles HTTP proxies only. Add the socksify gem to route Net::HTTP through a SOCKS5 proxy, or use Typhoeus with proxytype: :socks5. Copy the SOCKS host and port from your dashboard, since they differ from the HTTP gateway.

A 407 means proxy authentication failed. Confirm the username and password are in the right place for your client, and percent-encode any reserved characters in the password with CGI.escape. A 407 with correct credentials points to an account or IP allowlist issue in the dashboard.

Your connection is being reused. A rotating gateway assigns a new exit IP per TCP connection, so a persistent connection keeps the same IP. Create a fresh Net::HTTP object for each request, or send a Connection: close header, to force a new connection and a new IP.

Store them in environment variables and read them with ENV.fetch('PROXY_USER') and ENV.fetch('PROXY_PASS'). This keeps credentials out of source control and out of the URL. For local development, a tool like dotenv loads them from a file that you exclude from version control.

Yes. The proxy configuration is identical for any HTTP method. With Net::HTTP, build a Net::HTTP::Post, set its form data or body, and call http.request(req) on the same proxied object you would use for a GET. Faraday, HTTParty, and Typhoeus all expose a post method that takes the same proxy settings.

Using a proxy is legal, and it is a standard practice for testing, monitoring, and public-web data collection. What matters is how you use it: collect only publicly available data, respect each site's terms and rate limits, and follow the regional rules that apply to your work.