amphp/http-server
A non-blocking, concurrent HTTP/1.1 and HTTP/2 application server for PHP built on Revolt and Amp. It forwards requests to RequestHandler implementations and supports middleware, TLS, GZIP compression, and fiber-based concurrency.
What this package actually is. amphp/http-server is not a Laravel package and should not be evaluated as one. It is a process-owning, non-blocking HTTP/1.1 and HTTP/2 application server built on the Revolt event loop and Amp v3 coroutines (PHP fibers). Installing it via Composer is trivial; adopting it means giving up PHP-FPM's request-per-process model and the implicit guarantees Laravel is built on. The correct framing for the portfolio is: "a candidate runtime for a narrow set of high-concurrency surfaces," not "a library we add to the app."
Architecture fit. Strong fit for workloads defined by long-lived connections and high fan-out: WebSocket servers, server-sent events, streaming APIs, webhook ingestion, notification fan-out, and internal high-RPS JSON endpoints. Poor fit for anything that resembles a conventional Laravel CRUD application, because the library's central constraint is explicit and absolute: no blocking I/O in the handler. Nearly all of PHP's built-ins (PDO/mysqli, file_get_contents, curl_exec, sleep, the blocking Redis extension) halt the whole worker, which in a single-threaded event loop stalls every concurrent request, not just the offending one. Laravel's Eloquent, its filesystem adapter, its cache and queue drivers, and most of its ecosystem packages are blocking by default. The README's own sleep(5) example is precisely the failure mode a Laravel team will hit on day one.
The escape hatches exist but each carries cost: amphp/mysql, amphp/postgres, amphp/redis, amphp/file, amphp/http-client for non-blocking I/O, and amphp/parallel to push genuinely blocking work to a worker pool — which reintroduces IPC serialization overhead and a second failure surface.
Integration feasibility. Mechanically feasible, architecturally expensive:
Amp\Http\Server\Request/Response are Amp-native. It exposes a PSR-7 UriInterface, but there is no drop-in Symfony HttpFoundation or Laravel request adapter. You write the adapter, and it becomes load-bearing infrastructure you own forever.Technical risk. Medium-to-high, concentrated in four places:
createForBehindProxy() requires a trusted-proxy allowlist and a ForwardedHeaderType. Misconfiguration here silently breaks client-IP logging, rate limiting, and audit trails — a security-adjacent defect, not a cosmetic one.Key questions for the evaluation. What are the concurrency and latency targets that PHP-FPM + OPcache demonstrably cannot meet? Do we need HTTP/2 and WebSockets in the same process, or can a managed service cover it? What percentage of the target endpoints touch the database, and can those paths use amphp/mysql/amphp/postgres? Have we benchmarked Laravel Octane (Swoole/RoadRunner/FrankenPHP) first — it solves persistent-worker performance with far less disruption? Who owns this runtime in production, and do we have an exit plan if the project stalls?
Stack fit. Treat this as an adjacent runtime, not a replacement runtime. It owns its own process and its own listening socket; it cannot be hosted inside php-fpm or as a Laravel service provider. The viable shape is a Composer package inside the same monorepo (or a sibling service), deployed as a separate container behind the same load balancer, sharing auth contracts and observability conventions with the Laravel application.
Recommended architecture — sidecar first. Stand up the Amp server for exactly one bounded surface: WebSocket/SSE fan-out or a single high-RPS streaming endpoint. Laravel remains the system of record, the admin surface, and the home of all business logic. The sidecar handles connection lifecycle and transport only, and reaches back to Laravel through a non-blocking HTTP client for authorization decisions, caching the result briefly to keep fan-out cheap.
Migration path. Do not attempt a "port Laravel to Amp" project. It is unbounded and fails on the blocking-I/O constraint. The tractable path is endpoint-by-endpoint extraction of a new surface, never a rewrite of an existing one. If the goal is general application throughput rather than real-time capability, Octane is the lower-risk answer and this evaluation should conclude "no" early.
Compatibility checklist before any code is written:
amphp/http-server-router), body parsing, sessions, static content, and third-party CORS. Enumerate each as a separate dependency with its own maintenance status.createForBehindProxy() with a correct trusted-IP list.nghttp2 FFI acceleration: treat as a tuning step, not a prerequisite; it adds a native dependency to the image.Sequencing.
Maintenance. This is infrastructure, not an application dependency, and it will be maintained like infrastructure. Expect a permanent internal owner responsible for the runtime, the adapter, and the dependency graph of companion Amp packages. Version upgrades are planned work items with a staging rehearsal, not routine composer update noise — a major-version bump in Amp has historically been a breaking change across the whole call stack.
Support model. Community-supported OSS under MIT, no vendor SLA, no security-response commitment. The practical mitigation is version pinning, an internal fork-or-patch capability, and a documented fallback to the PHP-FPM implementation for the pilot surface. Escalate the bus-factor question to architecture review rather than absorbing it silently.
Scaling. Each worker is single-process and single-threaded; concurrency comes from cooperative scheduling, not parallelism. Scale out with more workers/Supervisor units and horizontally behind the load balancer. CPU-bound work — PDF generation, image processing, heavy serialization, synchronous encryption of large payloads — must be offloaded to amphp/parallel or to a queue, or it will serialize the worker. Memory is the sharper edge: long-lived WebSocket connections and per-coroutine buffers accumulate, so set and monitor connection ceilings (the direct-access constructor defaults to 10 connections per IP, 1,000 total, 1,000 concurrent requests — validate these against real traffic and expected NAT/proxy client-IP collapse).
Failure modes to instrument and runbook:
Forwarded/X-Forwarded-For misconfiguration → wrong client IPs in logs, rate limits, and audit records.Ramp-up. The real cost is cognitive, not licensing. Engineers must think in fibers and the event loop: understanding that a request handler is a coroutine, that await-style suspension is where interleaving happens, and that shared mutable state across coroutines is a hazard. Budget 2–4 weeks of structured onboarding for two to three engineers, plus a written internal standard covering the blocking-I/O prohibition, the approved non-blocking client libraries, and the adapter contract. Debugging across fibers produces less familiar stack traces, and there is no Laravel Telescope/Debugbar equivalent — expect slower incident diagnosis until the team has lived through a few. That learning investment is only justified if the pilot demonstrates a capability gap the current stack genuinely cannot close.
How can I help you explore Laravel packages today?