Request Tracing
Overview
Request Tracing makes it possible to capture detailed information about every HTTP request that passes through a route. It serves as a troubleshooting tool when a route does not behave as expected — instead of guessing why a request fails, the admin sees exactly what happens: method, URI, status code, remote IP, and response details.
License feature key: request_debugging
How it works
Request Tracing is based on the caddy-trace plugin for Caddy. When tracing is enabled for a route, a trace handler is inserted into the Caddy handler chain. This handler logs two entries for every request:
- Incoming Request: method, URI, host, remote IP, user agent, headers, query parameters
- Outgoing Response: status code, response size, response headers
The trace entries are displayed in real time in the Debug tab of the Edit Route modal, with an automatic refresh every 3 seconds.
Handler position in the route chain
1. defender (Bot Blocker)
2. trace (Request Tracing) ← logs the entire lifecycle
3. headers (Custom Headers)
4. rate_limit
5. mirror (Request Mirroring)
6. encode (compression)
7. reverse_proxy (backend)
The trace handler sits at position 2 (after the Bot Blocker) and is a wrapping middleware — it logs the request before processing and the response afterwards. This lets it capture the final status code regardless of which handler produced the response.
Configuration
Enable tracing
- Open the route (Edit modal → Debug tab)
- Enable the Request Tracing toggle
- Save the route
Tracing can also be enabled when creating a new route (in the "Create new route" card).
Viewing trace entries
- Open the route (Edit modal → Debug tab)
- Trace entries appear automatically (auto-refresh every 3 seconds)
- Each entry shows:
| Column | Description |
|---|---|
| Time | Timestamp of the request (HH:MM:SS) |
| Method | HTTP method (GET, POST, PUT, DELETE, etc.) |
| URI | Requested path (e.g. /api/data) |
| Status | HTTP status code with color coding |
| Remote IP | IP address of the requesting client |
Status code color coding
| Color | Status range | Meaning |
|---|---|---|
| Green | 2xx | Successful requests |
| Yellow | 4xx | Client errors (404, 403, etc.) |
| Red | 5xx | Server errors (502, 503, etc.) |
Clear button
The "Clear" button removes all displayed trace entries from the view. Polling continues — new requests appear automatically. The log file is not deleted.
Badge in the route list
When tracing is active for a route, an amber "Debug" badge appears in the route list. This lets the admin see at a glance which routes have tracing enabled.
The badge is only shown for HTTP routes (not for L4/TCP routes).
Limitations
- HTTP routes only: L4/TCP routes do not support tracing (caddy-trace is an HTTP handler)
- No persistence: Trace data is only stored in the Caddy log file, not in the database
- No export: Trace entries cannot be exported as CSV/JSON
- No URI filter: All requests to the route are traced, no selective tracing possible
- Performance: Tracing creates additional log entries — on high-traffic routes it should only be enabled temporarily
Technical details
caddy-trace plugin
Repository: github.com/greenpau/caddy-trace
Handler name: trace (http.handlers.trace)
Go module: github.com/greenpau/caddy-trace
Handler config
{
"handler": "trace",
"tag": "route-{routeId}",
"response_debug_enabled": true
}
- tag: Unique identifier per route (
route-1,route-2, etc.) — used to filter log entries - response_debug_enabled: Enables response logging (status code, response size, response headers)
Log pipeline
- caddy-trace writes Zap JSON to stdout
- Supervisord pipes Caddy stdout via
teeto/data/caddy/caddy-stdout.log - The trace API (
GET /api/v1/routes/:id/trace) reads this file - Entries are filtered by
tag === "route-{id}" - Incoming and outgoing entries are merged via
request_id
Log format (caddy-trace output)
Incoming Request:
{
"level": "debug",
"time": "2026-03-27T21:45:54.741Z",
"msg": "debugging request",
"request_id": "f9c59915-9071-419a-8ca2-46a035bfa356",
"direction": "incoming",
"tag": "route-1",
"method": "GET",
"host": "nas.domaincaster.com",
"uri": "/",
"remote_addr": "54.36.233.20",
"user_agent": "curl/8.17.0",
"headers": { "Accept": "*/*" }
}
Outgoing Response:
{
"level": "debug",
"time": "2026-03-27T21:45:54.742Z",
"msg": "debugging response",
"request_id": "f9c59915-9071-419a-8ca2-46a035bfa356",
"direction": "outgoing",
"tag": "route-1",
"status_code": 302,
"response_size": 0,
"response_headers": { "Location": ["/route-auth/login?..."] }
}
Database
| Column | Type | Default | Description |
|---|---|---|---|
debug_enabled |
INTEGER | 0 | Request Tracing enabled (0/1) |
Migration version 27 (add_debug_enabled) — created on 2026-03-27.
Backup/Restore
debug_enabled is included in backup/restore. Trace data (the log file) is not exported.
UI integration
- Create card: Toggle "Request Tracing" inside
http-fields(hidden on L4) - Edit modal: dedicated "Debug" tab with toggle + trace log container
- Debug tab is hidden for L4 routes
- Polling: auto-refresh every 3 seconds while the Debug tab is active
- Polling stops on tab switch or modal close
- Badge: amber "Debug" badge in the route list