# 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.


## Go: http.Transport

```go
package main

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

func main() {
	proxyURL, _ := url.Parse("http://USER-cc-us:PASS@res.proxshift.com: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:PASS@res.proxshift.com: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:PASS@res.proxshift.com: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

**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.

Source: https://proxshift.com/guides/go-and-php-proxies
