Request Lifecycle
Relevant source files
The following files were used as context for generating this wiki page:
The Request Lifecycle in kamal-proxy describes the end-to-end journey of an HTTP request from the moment it enters the proxy until the response is returned to the client. The system employs a layered middleware architecture and a service-oriented routing mechanism to manage security, traffic shaping, and load balancing across multiple target upstreams.
Key stages include initial logging and context initialization, application of security filters (IP allow/deny lists), traffic management (rate limiting, redirects), and finally, target selection via the Load Balancer.
High-Level Request Flow
When a request is received, it passes through a series of global and service-specific handlers. The Service.ServeHTTP method acts as the entry point for requests matched to a specific service, tracking inflight metrics before handing the request to the middleware chain.
Middleware Pipeline
The proxy constructs a sophisticated middleware pipeline for each service. The order of these middlewares is critical for ensuring that security checks occur before resource-intensive operations or content modifications.
Order of Execution
- Logging & Trace Context: Initializes the request context, unique IDs, and trace information.
- Request Deadline: Bounds the total time a request can take.
- Error Intercept: Captures specific upstream error codes to replace with custom pages.
- Error Pages: Provides the framework for rendering HTML error responses.
- Compression: Handles Gzip/Brotli/Zstd encoding of the response.
- ACME/TLS: Handles HTTP-01 challenges for automated certificate renewal.
- Client IP: Populates
X-Forwarded-Forbased on configured headers.
Sources: internal/server/service.go:699-760, internal/server/logging_middleware.go:61-75
Request Deadline Management
The RequestDeadlineMiddleware ensures that requests do not hang indefinitely. Unlike standard timeouts, it covers the entire duration including response streaming, but exempts "long-lived" connections like WebSockets and Server-Sent Events (SSE).
Security and Traffic Filtering
Before a request reaches the load balancer, several layers of filtering are applied within serviceRequestWithTarget:
| Check | Description | Logic |
|---|---|---|
| Deny List | Immediate rejection of blocked IPs or User-Agents. | Checked first; address on both Allow/Deny is denied. |
| Allow List | Restricts access to specific CIDR ranges. | Bypassed for internal requests/health checks. |
| TLS Check | Ensures TLS is present if the service requires it. | Returns 503 if HTTPS is missing. |
| Rate Limit | Prevents flooding by capping requests per second. | Uses token bucket per client IP (/64 for IPv6). |
| Basic Auth | Challenges users for credentials. | CLI-side hashed; no plaintext in transit. |
Sources: internal/server/service.go:768-805, internal/server/service.go:214-230
Routing and Load Balancing
Once a request passes all filters, it is prepared for the upstream target.
Path Rewriting and Redirection
The proxy evaluates both static and dynamic redirect/rewrite rules. Rewrites change the path seen by the target (useful for SPAs), while redirects send a 3xx response to the client.
- Static Rules: Defined in service configuration.
- Dynamic Rules: Fetched from a remote
--redirects-source. - Canonical Host: Forces redirection to a primary domain (e.g., non-www to www).
Sources: internal/server/redirect_rules.go:107-133, internal/server/service.go:851-893
Target Selection
The LoadBalancer manages the selection of a healthy target. It distinguishes between Active and Rollout slots, allowing for canary deployments.
- Slot Selection: Based on
RolloutControllerlogic (percentage or allowlist). - Read/Write Split: GET/HEAD requests may be routed to
Readertargets, while mutations (POST/PUT/DELETE) go toWriters. - Affinity: If
SessionAffinityis enabled, a cookie pins the client to a specific target.
Response Handling
As the response returns from the upstream target, it flows back through the middleware stack in reverse order:
- Error Interception: If the status code matches
InterceptErrorStatuses, the body is replaced with a custom error page. - Compression: If enabled and the content type is compressible, the body is encoded.
- Logging: The
LoggingMiddlewarerecords the final status code, bytes written, and duration before completing the request cycle.
Sources: internal/server/error_page_middleware.go:70-85, internal/server/logging_middleware.go:77-124
Summary
The kamal-proxy request lifecycle is designed for resilience and security. By separating global concerns (logging) from service concerns (auth, rate limiting) and employing a robust load balancing strategy, it provides a highly configurable path for traffic while protecting upstreams from excessive or unauthorized load.