clue/http-proxy-react
Async HTTP proxy with support for forward and reverse proxying (including HTTPS via CONNECT), built on ReactPHP. Useful for tunneling, debugging and routing HTTP(S) traffic in event-driven PHP apps, with streaming I/O and low overhead.
Start by installing clue/http-proxy-react via Composer:
composer require clue/http-proxy-react:^1.0
Then, create a minimal proxy server in a long-running script (proxy.php):
<?php
require 'vendor/autoload.php';
$loop = React\EventLoop\Loop::get();
$proxy = new Clue\React\HttpProxy\HttpProxyMiddleware();
$server = new React\Http\Server($loop, function ($request) use ($proxy) {
return $proxy($request);
});
$server->listen(new React\Socket\Server('127.0.0.1:8080', $loop));
echo "Proxy listening on http://127.0.0.1:8080\n";
$loop->run();
Run it: php proxy.php. Now route requests via curl -x http://127.0.0.1:8080 http://example.com — it will proxy without blocking.
Custom routing via middleware composition: Wrap HttpProxyMiddleware with your own middleware to intercept before forwarding.
Example: add API key header conditionally:
$proxy = new Clue\React\HttpProxy\HttpProxyMiddleware();
$customProxy = function ($request) use ($proxy) {
if ($request->getUri()->getPath() === '/api/v1') {
$request = $request->withHeader('X-API-Key', getenv('API_KEY'));
}
return $proxy($request);
};
Target rewriting: Modify the upstream destination before forwarding:
$proxy = new Clue\React\HttpProxy\HttpProxyMiddleware([
'uri' => 'http://internal-backend:3000', // default upstream
]);
// Override per-request
$server = new React\Http\Server($loop, function ($request) use ($proxy) {
$target = $request->getHeaderLine('X-Upstream') ?: 'http://localhost:8081';
$proxy->setUri(new Psr\Http\Message\UriInterface($target)); // Not public API! Use composition instead.
});
✅ Better: Create a new proxy per request with new HttpProxyMiddleware(['uri' => $targetUri]).
Forward proxy for debugging: Combine with react/http-client and logging:
$logger = new class implements LoggerInterface { ... };
$proxy = new Clue\React\HttpProxy\HttpProxyMiddleware();
$server = new React\Http\Server($loop, function ($request) use ($proxy, $logger) {
$logger->info('Forwarding', ['method' => $request->getMethod(), 'uri' => $request->getUri()]);
return $proxy($request);
});
Long-running gateways: Use with clue/reactphp-flux for high-concurrency filtering, or evenement/evenement for custom events on request/response pairs.
No built-in HTTPS upstream support for forward proxy: To proxy HTTPS target servers in forward mode, you must enable allow_self_signed in the underlying HTTP client (via config). Pass ['verify' => false] carefully — use with caution in production.
Memory leaks: Never reuse the same HttpProxyMiddleware instance across requests while mutating its internal state. Instead, instantiate per-request or clone cleanly.
Missing request body buffering: The proxy does not buffer the request body. For header-based routing that inspects the body (e.g., JSON content), combine with clue/reactphp-body:
$bodyParser = new Clue\React\Http\Middleware\BodyParserMiddleware();
$proxy = new Clue\React\HttpProxy\HttpProxyMiddleware();
$middleware = new Clue\React\Http\Middleware\BufferMiddleware($bodyParser, function ($bufferedRequest) use ($proxy) {
// Now `$bufferedRequest->getBody()` is fully available
return $proxy($bufferedRequest);
});
Debugging tip: Enable ReactPHP’s event loop logging with React\Debug\Node::dumpEventLoop() to catch stalled connections or unhandled rejections.
Configuring the underlying client: The proxy internally uses react/http-client. You can inject a custom client via the constructor’s third argument if you need proxy-specific timeouts, redirects, or proxy chains:
$client = new React\Http\Client($loop, [
'timeout' => 10,
'follow_redirects' => false,
]);
$proxy = new Clue\React\HttpProxy\HttpProxyMiddleware([], [], $client);
How can I help you explore Laravel packages today?