All guides
DEVELOPER GUIDES · 8 MIN READ

How to configure a Ruby Net::HTTP proxy

Route Ruby Net::HTTP through an HTTP or HTTPS proxy, keep credentials separate, close sessions cleanly, and validate the target response.

How to configure a Ruby Net::HTTP proxy

Quick answer: configure Ruby Net::HTTP with the proxy host and port, enable Transport Layer Security (TLS) for an HTTPS target, and bind proxy credentials at runtime. Accept only a bounded response with the expected status and content; CONNECT alone does not validate the target result.

Prerequisites

  • Ruby 3.4.11 (tested); the example uses net/http, uri, and OpenSSL from this runtime.
  • An HTTP or HTTPS proxy endpoint permitted for this request. Ruby 3.4 supports TLS to the proxy separately from TLS to the target.
  • A permitted HTTPS target and a stable marker or parsed field that defines a useful response.

Save the complete example as proxy_get.rb. Set PROXY_URL to the http:// or https:// proxy host and port without user information. When authentication is required, inject both PROXY_USER and PROXY_PASSWORD; Net::HTTP.new passes them to the proxy separately from the target URL. Defaults use https://example.com/ and Example Domain; TARGET_URL and EXPECTED_MARKER allow an authorized test target. The response body is capped at 1 MiB and no retry is attempted.

Warning: First send one bounded request to a permitted test target and confirm its status and expected content; leave production jobs disabled until that check passes. For Basic proxy authentication, an http:// proxy exposes the login to observers on the client-to-proxy network path. CONNECT only establishes the tunnel; TLS to the target encrypts application traffic carried inside it, not the earlier proxy login. Ruby 3.4 can use TLS to an https:// proxy endpoint with certificate verification; enable that only when the proxy supports it. Keep credentials in a secret manager or runtime binding, rotate them if exposed, and check account usage after unexpected traffic.

Keep proxy credentials outside the URL

Net::HTTP.new accepts the target address and port, followed by the proxy address, proxy port, username, and password. The example keeps PROXY_URL free of userinfo and passes optional credentials as separate runtime bindings. Replace the bracketed placeholders with values supplied through a secret store; do not commit literal credentials:

PROXY_URL=http://proxy.example:3128
PROXY_USER=<PROXY_USER>
PROXY_PASSWORD=<PROXY_PASSWORD>

use_ssl below enables TLS to the target after the proxy connection is established; it does not enable TLS to the proxy. The separate final p_use_ssl argument to Net::HTTP.new enables TLS to an https:// proxy. Use that option only when the provider supports an HTTPS proxy endpoint and its certificate validates.

Save this as proxy_get.rb. The example bounds connection open at 5 seconds and individual read/write operations at 10 seconds; the proxy timeout guide explains why these socket limits do not define one total job deadline. It accepts only 200 OK and rejects proxy 407:

require 'net/http'
require 'openssl'
require 'uri'

MAX_BODY_BYTES = 1 << 20

def required_env(name)
  value = ENV[name].to_s.strip
  raise "missing required environment binding: #{name}" if value.empty?

  value
end

def read_response(http, target)
  request = Net::HTTP::Get.new(target)
  status = nil
  body = +''

  http.request(request) do |response|
    status = response.code.to_i
    if status == 407
      raise 'proxy authentication or CONNECT negotiation returned HTTP 407'
    end

    response.read_body do |chunk|
      if body.bytesize + chunk.bytesize > MAX_BODY_BYTES
        raise 'response body exceeded local cap'
      end
      body << chunk
    end
  end

  [status, body]
end

begin
  target = URI(ENV.fetch('TARGET_URL', 'https://example.com/'))
rescue URI::InvalidURIError
  warn 'TARGET_URL is invalid'
  exit 1
end
unless %w[http https].include?(target.scheme) && !target.host.nil? && target.user.nil? && target.password.nil?
  warn 'TARGET_URL must be an HTTP or HTTPS URL without credentials'
  exit 1
end
expected_marker = ENV.fetch('EXPECTED_MARKER', 'Example Domain')
raise 'EXPECTED_MARKER must be non-empty' if expected_marker.empty?
begin
  proxy = URI(required_env('PROXY_URL'))
rescue URI::InvalidURIError
  warn 'PROXY_URL is not a valid URI'
  exit 1
end
unless %w[http https].include?(proxy.scheme) && !proxy.host.nil? && proxy.user.nil? && proxy.password.nil?
  raise 'PROXY_URL must be an HTTP or HTTPS proxy URL without credentials'
end

proxy_user = ENV['PROXY_USER']
proxy_password = ENV['PROXY_PASSWORD']
if proxy_user.nil? != proxy_password.nil? || (!proxy_user.nil? && (proxy_user.empty? || proxy_password.empty?))
  raise 'PROXY_USER and PROXY_PASSWORD must be supplied together and non-empty'
end

http = Net::HTTP.new(
  target.host,
  target.port,
  proxy.host,
  proxy.port,
  proxy_user,
  proxy_password,
  nil,
  proxy.scheme == 'https'
)
http.use_ssl = target.scheme == 'https'
http.open_timeout = 5
http.read_timeout = 10
http.write_timeout = 10
http.max_retries = 0

begin
  http.start do |session|
    status, body = read_response(session, target)
    raise 'target returned a non-accepted HTTP status' unless status == 200
    raise 'target marker was absent' unless body.include?(expected_marker)

    puts "status=#{status} marker=present"
  end
rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout, SocketError, EOFError,
       Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ETIMEDOUT,
       OpenSSL::SSL::SSLError, Net::HTTPBadResponse, Net::HTTPFatalError, Net::ProtocolError
  warn 'request failed in transport or proxy negotiation'
  exit 1
end

Expected output for a successful response:

status=200 marker=present

The Net::HTTP.start block closes the connection when it exits. open_timeout covers opening the connection to the proxy. read_timeout and write_timeout apply to individual socket operations, not the total request duration. The response block rejects a 407 before reading its body, then bounds accepted body data at 1 MiB. With Ruby 3.4.11, an HTTPS CONNECT 407 raised a transport exception before a response object; the example emits a generic message to avoid logging proxy details. Malformed URI, TLS, and CONNECT failures exit with a generic message; the proxy URI and exception details never reach output.

This core example uses one attempt. If a worker adds retries for an idempotent GET, classify the failure first, honor a valid rate-limit Retry-After instruction, and keep a job-level deadline. DNS, TLS, connection, configuration, and proxy-authentication failures should stop immediately because repeating an invalid password or an unreachable endpoint does not repair the route.

Check the output the job needs

Use an application-level contract rather than counting a successful request call:

input:  permitted HTTPS target + HTTP proxy host/port + expected marker
output: status=200, marker present, body <= 1 MiB, session closed

The marker stands for the required application field or schema. A target can return a valid HTTP status with an error page, login form, or challenge; reject content that fails the parser contract. A Net::HTTP session is bound to one host and port. To check a trusted IP endpoint on another host, create a separate Net::HTTP instance for that host with the same proxy configuration, TLS verification, and timeout limits; send no target credentials. A provider may assign a different exit to the new connection, so check its documented session policy separately. The IP response describes only that check request, not the earlier target connection.

Observation Boundary Next decision
Proxy URL has credentials or an unsupported scheme Local configuration Remove userinfo and use a documented HTTP proxy endpoint
Open/read/TLS exception before a response Client, proxy, or CONNECT Check proxy host, port, certificate, and reachability; do not retry blindly
407 Proxy authentication Repair proxy credentials or entitlement; keep them away from target headers
401 or 403 after CONNECT Target policy Check target login, permission, or target-side rules
429 Target rate limit Follow the rate-limit and Retry-After guide and reduce request rate; do not change exits to evade the limit
3xx redirect Target response Inspect Location and permit the destination before sending a new request
502, 503, or 504 Temporary gateway or target response Defer or retry only under an explicit policy that honors Retry-After
HTTP 200 with no marker Application validation Reject the result and inspect the content or parser
Body exceeds 1 MiB Local resource policy Reject or define another bounded streaming rule

For the same phase-by-phase view in a terminal, read the curl proxy guide. The proxy client settings guide covers cases where an application-specific route differs from the operating system.

When moving the example into a worker, preserve the configured proxy scheme, timeouts, and status/body checks before the job accepts a record.

Sources and further reading

ProxyLaneTraffic never expires

Premium residential proxies
From $2/GB

Scale your workflows with the tools you already use. Rotating or sticky sessions up to 72 hours.

Try 350 MB for $1.95 View plans

Keep reading

Amazon Scraper API vs Proxy: Choose a Product Data Source

Compare seller APIs, licensed Amazon product data and proxy page checks by record, access scope and reuse rights.

Read guide

Antidetect browser proxy setup: choose a profile guide

Choose the right anti-detect browser proxy guide, map the shared verification steps, and keep account access separate from the network route.

Read guide

Best Proxies for Market Research: Choose by Sample and Cost

Our picks for market research: ProxyLane for small, intermittent projects, plus options for regional tracking, monthly collection and managed extraction.

Read guide