Caddy Parrot - a simple HTTP echo service

Caddy Parrot is a lightweight HTTP echo service that repeats everything your clients, reverse proxies, or load balancers send. It’s built entirely in Caddy using templates, with no external scripts or PHP required. Good for debugging headers, TLS details, and request bodies in a clean, self-contained setup.

Caddyfile:

example.com {
	
	request_body {
		max_size 1MB
	}

	templates

	respond <<PARROT
		## Request Summary:
		Method         : {{ .Req.Method }}
		URI            : {{ .Req.RequestURI }}
		Protocol       : {{ .Req.Proto }}
		Remote Address : {{ .Req.RemoteAddr }}
		Server         : {{ .Req.Host }}
		Connection     : {{ if .Req.TLS }}HTTPS{{ else }}HTTP{{ end }}
		Timestamp      : {{ now | date "2006-01-02 15:04:05 UTC" }}
		
		{{ if .Req.TLS -}}
		## TLS Details:
		Version        : {tls_version}
		Cipher Suite   : {tls_cipher}
		Protocol       : {{ .Req.TLS.NegotiatedProtocol }}
		SNI            : {{ .Req.TLS.ServerName }}
		{{- end }}

		## Headers:
		{{ if .Req.Host }}Host: {{ .Req.Host }}{{ end }}
		{{ range $header, $values := .Req.Header }}{{ range $values }}{{ printf "%s: %s\n" $header . }}{{ end }}{{ end -}}
		
		{{ if .Req.URL.RawQuery }}
		## Query Parameters:
		{{ range $param, $values := .Req.URL.Query }}{{ range $values}}{{printf "%s: %s\n" $param . }}{{ end }}{{ end -}}
		{{ end -}}
		
		{{ if or (eq .Req.Method "POST") (eq .Req.Method "PUT") (eq .Req.Method "PATCH") }}
		## Request Body:
		{{ placeholder "http.request.body" }}
		{{ end }}
		PARROT
}

Example:

$ curl -k -X POST \
>   'https://example.com/api/test?param1=value1&param1=value2&param2=single&empty=' \
>   -H 'Content-Type: application/json' \
>   -H 'Authorization: Bearer token123' \
>   -H 'Custom-Header: first-value' \
>   -H 'Custom-Header: second-value' \
>   -H 'X-Test: debug' \
>   -H 'Accept: application/json, text/plain' \
>   -d '{"name":"test","values":[1,2,3],"nested":{"key":"value"}}'
## Request Summary:
Method         : POST
URI            : /api/test?param1=value1&param1=value2&param2=single&empty=
Protocol       : HTTP/2.0
Remote Address : 127.0.0.1:62983
Server         : example.com
Connection     : HTTPS
Timestamp      : 2025-10-17 17:10:31 UTC

## TLS Details:
Version        : tls1.3
Cipher Suite   : TLS_AES_128_GCM_SHA256
Protocol       : h2
SNI            : example.com

## Headers:
Host: example.com
Accept: application/json, text/plain
Authorization: Bearer token123
Content-Length: 57
Content-Type: application/json
Custom-Header: first-value
Custom-Header: second-value
User-Agent: curl/8.16.0
X-Test: debug

## Query Parameters:
empty:
param1: value1
param1: value2
param2: single

## Request Body:
{"name":"test","values":[1,2,3],"nested":{"key":"value"}}
11 Likes