Guzzle proxy
A Guzzle proxy is a Guzzle HTTP client configured to tunnel every request through an upstream proxy. Pass the Aethyn endpoint in the proxy option — on the client or per request — and each call exits from a real residential IP.
Why a residential Guzzle proxy
PHP scrapers and API clients that leave the server on a datacenter IP get the same two failures everywhere: blocks on protected targets, and geo-wrong HTML on stores, SERPs, and paywalls. A Guzzle HTTP proxy fixes both by substituting an ISP-assigned exit without changing how you call $client->get(). Aethyn keeps the config to one string: http://user:pass@proxy.aethyn.io:2099, with country, city, and sticky session encoded on the username. Omit a session id and Guzzle rotates per request, which is what you want for stateless crawls. Add -session-<id>-lifetime-<minutes> when a login, cart, or cookie jar has to survive. HTTPS is not a second proxy; Guzzle sends CONNECT on port 2099, so one proxy option covers both schemes. Set timeout on the client. Residential paths are slower than a local cURL to a CDN, and a missing timeout turns a dead exit into a worker that never returns.
Setup steps
- 1Install Guzzle: composer require guzzlehttp/guzzle.
- 2Create a client (or per-request options) with the proxy option.
- 3Use the full http://user:pass@host:port form.
- 4Add targeting suffixes to the username as needed.
Code
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client([
'proxy' => 'http://aethyn-XXXXX-country-us:PASSWORD@proxy.aethyn.io:2099',
'timeout' => 30,
]);
$res = $client->get('https://httpbin.org/ip');
echo $res->getBody();<?php
use GuzzleHttp\Client;
$client = new Client(['timeout' => 30]);
$user = 'aethyn-XXXXX-country-us-session-abc123-lifetime-10';
$res = $client->get('https://example.com/account', [
'proxy' => "http://{$user}:PASSWORD@proxy.aethyn.io:2099",
]);
echo $res->getStatusCode();<?php
use GuzzleHttp\Client;
$client = new Client([
'proxy' => 'socks5h://aethyn-XXXXX:PASSWORD@proxy.aethyn.io:1099',
'timeout' => 30,
]);
echo $client->get('https://httpbin.org/ip')->getBody();<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
$client = new Client([
'proxy' => 'http://aethyn-XXXXX:PASSWORD@proxy.aethyn.io:2099',
'timeout' => 30,
]);
try {
echo $client->get('https://httpbin.org/ip')->getBody();
} catch (ClientException $e) {
if ($e->getResponse() && $e->getResponse()->getStatusCode() === 407) {
fwrite(STDERR, "proxy auth failed — check username suffixes\n");
}
throw $e;
} catch (ConnectException $e) {
fwrite(STDERR, "exit timed out — retry on a fresh IP\n");
}Replace aethyn-XXXXX and PASSWORD with your dashboard credentials. See the full targeting reference and protocol/port list.
Troubleshooting
The Guzzle failures that look like 'the proxy is broken' are almost always 407, cURL error 28 (timeout), or CONNECT failures on HTTPS. A 407 from Guzzle means the proxy rejected auth: the username must be aethyn-XXXXX plus targeting suffixes, and the password must match the dashboard — putting -country-us on the password side of the URL is the usual paste error. Timeouts need an explicit 'timeout' => 30 on the client; Guzzle's default can wait far longer than a residential hop should. If HTTP targets work and HTTPS throws a cURL error 56 or 35, Guzzle is not tunnelling CONNECT through the HTTP proxy: use an http:// proxy URL, not https://, in the proxy option. SOCKS5 is Guzzle's socks5h:// scheme on port 1099 and requires the cURL extension compiled with SOCKS support; without it Guzzle will ignore the scheme or fail at request time.
Tips
- Set a timeout — residential routes are slower than datacenter.
- Reuse one client instance across requests.
- For cURL extension users, the CURLOPT_PROXY option works the same way.
- Use socks5h:// (not socks5://) so DNS resolves at the proxy.