How to Log Raw Request Body Bytes at the Proxy Level in Caddy

1. The problem I’m having:

I’m using Caddy as a reverse proxy to a Flask app running on gunicorn. I want to log the raw request body bytes (POST request) from Caddy’s perspective, specifically to debug and inspect the actual content.

In Flask, I already do this with:

@app.before_request
def log_wsgi_environ():
    import pprint
    print("=" * 40)
    pprint.pprint(request.environ)
    print("Raw request body(bytes):")
    print(request.get_data())
    print("=" * 40)

I want similar raw request body visibility at the Caddy reverse proxy level, after proxying, i.e what does caddy send to my origin after proxying user requests?

How can I configure Caddy to dump the raw body bytes, ideally in logs (stdout or JSON)? I’m aware of the request_body directive and placeholders, but I need the raw body printed or stored in logs.

2. Error messages and/or full log output:

{
  "level": "info",
  "ts": 1749288416.259085,
  "logger": "http.log.access.log0",
  "msg": "handled request",
  "request": {
    "remote_ip": "127.0.0.1",
    "method": "POST",
    "uri": "/",
    "headers": {
      "Content-Length": ["12"]
    }
  },
  "bytes_read": 12,
  "size": 3159,
  "status": 200,
  "resp_headers": {
    "Content-Type": ["text/html; charset=utf-8"]
  }
}

I want to see those 12 bytes logged (e.g., title=TestBook or whatever raw payload was actually sent). How can I do this?

3. Caddy version:

v2.10.0 h1:fonubSaQKF1YANl8TXqGcn4IbIRUDdfAkpcsfI/vX5U=

4. How I installed and ran Caddy:

Grabbed the lastest binary(v2.10.0) from GitHub and installed it as follows:-

sudo dpkg -i caddy_2.10.0_linux_amd64.deb

a. System environment:

Linux parrot 6.12.12-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.12-1parrot1 (2025-02-27) x86_64 GNU/Linux

b. Command:

caddy run

c. Service/unit/compose file:

N/A

d. My complete Caddy config:

:2018 {
	reverse_proxy localhost:8000 {
	}
	log {
        output stdout
        format json
        level DEBUG
    }
}

5. Links to relevant resources:

reverse proxy

You can use the log_append directive to include the {http.request.body} placeholder (see the docs) in the JSON access logs.

Here’s a basic example:

:2018 {
  reverse_proxy localhost:8000

  log_append request_body {http.request.body}

  log {
    output stdout
    format json
    level DEBUG
  }
}

The log_append directive is the option I would choose in most cases. It’s simple, built-in, and logs the request body directly.

As an alternative, there’s also a plugin I’ve written: caddy-placeholder-dump.

Here’s an example from the plugin’s README:

Dump Request Body

Log the request body to a file when the query parameter trace=true is used:

route /api/* {
  @dump_body {
    query trace=true
  }

  placeholder_dump @dump_body {
    content "{time.now.unix}: {method} request from {client_ip} with body: {http.request.body}"
    file "/var/log/caddy/api_trace.log"
  }

  reverse_proxy localhost:9001
}
2 Likes