Integrations · Intermediate

Proxies in Go and PHP: net/http Transport, x/net/proxy, cURL and Guzzle

Both languages give you the proxy at the transport layer, which is exactly where rotation and connection reuse are decided. Two idioms each, and you control the exit precisely.

2 min read 6 sections Updated Published

Go: http.Transport#

Go
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"
)

func main() {
	proxyURL, _ := url.Parse("http://USER-cc-us:[email protected]:9000")
	client := &http.Client{
		Timeout: 45 * time.Second,
		Transport: &http.Transport{
			Proxy:             http.ProxyURL(proxyURL),
			DisableKeepAlives: true, // new connection = new exit on the rotating gateway
		},
	}
	resp, err := client.Get("https://api.ipify.org")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}

Leave DisableKeepAlives at its default (false) for sticky work: the transport reuses connections and therefore the exit. Use one Transport per session id when you run parallel sticky flows.

Go: choosing the proxy per request#

Go
tr := &http.Transport{
	Proxy: func(r *http.Request) (*url.URL, error) {
		sid := r.Header.Get("X-Session") // your own hint, never sent to the proxy
		r.Header.Del("X-Session")
		return url.Parse(fmt.Sprintf("http://USER-cc-de-sid-%s-ttl-10m:[email protected]:9000", sid))
	},
}

Go: SOCKS5#

Go
import "golang.org/x/net/proxy"

dialer, err := proxy.SOCKS5("tcp", "res.proxshift.com:9001", &proxy.Auth{User: "USER-cc-us", Password: "PASS"}, proxy.Direct)
if err != nil { panic(err) }
tr := &http.Transport{Dial: dialer.Dial}
client := &http.Client{Transport: tr, Timeout: 45 * time.Second}

PHP: cURL#

PHP
<?php
$ch = curl_init("https://api.ipify.org");
curl_setopt_array($ch, [
    CURLOPT_PROXY          => "http://res.proxshift.com:9000",
    CURLOPT_PROXYUSERPWD   => "USER-cc-us:PASS",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CONNECTTIMEOUT => 15,
    CURLOPT_TIMEOUT        => 45,
    CURLOPT_FORBID_REUSE   => true, // new exit per call on the rotating gateway
]);
echo curl_exec($ch);

// SOCKS5 with remote DNS
curl_setopt($ch, CURLOPT_PROXY, "res.proxshift.com:9001");
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);

PHP: Guzzle#

PHP
<?php
use GuzzleHttp\Client;

$sticky = "http://USER-cc-de-city-berlin-sid-cart42-ttl-15m:[email protected]:9000";
$client = new Client(['proxy' => $sticky, 'timeout' => 45, 'connect_timeout' => 15]);

$r = $client->get('https://api.ipify.org');
echo $r->getBody();

Checklist#

  • Reuse connections for sticky flows, disable reuse for wide rotation.
  • Timeouts scaled to the exit type; one retry on transport errors.
  • Never log the proxy URL: it contains the password. Log the session id instead.

Questions people ask#

Does Go's http.ProxyFromEnvironment work?

Yes: export HTTPS_PROXY and HTTP_PROXY with the ProxShift URL and use http.ProxyFromEnvironment as the Transport's Proxy function. NO_PROXY excludes local hosts.

Ready when you are

Run it for real.

Create an account, top up $20 and paste the endpoint from this guide into your tool. Traffic you buy never expires.