Handle multiple request_body directive on different path

1. The problem I’m having:

Hello,

I currently want to modify the request_body directive for the path :

/api/sends/*

this api is used to let the user uploading files in the application. I already by default setup a request body of 100KB.

I try to resolve this by using the matcher with the directive request_body but it is not working as expected (see error and Caddyfile).
Did i miss something ?

Regards,

BBA

2. Error messages and/or full log output:

{
    "level": "error",
    "ts": 1700575275.1537004,
    "logger": "http.log.error",
    "msg": "{id=jfxqaftd5} requestbody.errorWrapper.Read (requestbody.go:63): HTTP 413: http: request body too large",
    "request": {
        "remote_ip": "192.168.1.1",
        "remote_port": "44120",
        "client_ip": "192.168.1.1",
        "proto": "HTTP/2.0",
        "method": "POST",
        "host": "vaultwarden.one4all.icu",
        "uri": "/api/sends/25a594c0-df15-47a8-9829-2673ccca1c82/file/c07a1ec1003ce08be9da81e73792c794d30cc5e284183a30df47eadcc7cf65eb",
        "headers": {
            "Content-Length": [
                "478029"
            ],
            "Sec-Ch-Ua": [
                "\"Brave\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\""
            ],
            "Sec-Ch-Ua-Mobile": [
                "?0"
            ],
            "User-Agent": [
                "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
            ],
            "Content-Type": [
                "multipart/form-data; boundary=----WebKitFormBoundaryJsEDO73v7v7yDHzU"
            ],
            "Sec-Gpc": [
                "1"
            ],
            "Origin": [
                "https://vaultwarden.one4all.icu"
            ],
            "Accept-Encoding": [
                "gzip, deflate, br"
            ],
            "Authorization": [],
            "Sec-Ch-Ua-Platform": [
                "\"Linux\""
            ],
            "Accept-Language": [
                "fr-FR,fr;q=0.5"
            ],
            "Device-Type": [
                "9"
            ],
            "Bitwarden-Client-Version": [
                "2023.10.0"
            ],
            "Accept": [
                "*/*"
            ],
            "Sec-Fetch-Mode": [
                "cors"
            ],
            "Sec-Fetch-Dest": [
                "empty"
            ],
            "Bitwarden-Client-Name": [
                "web"
            ],
            "Sec-Fetch-Site": [
                "same-origin"
            ]
        },
        "tls": {
            "resumed": true,
            "version": 772,
            "cipher_suite": 4867,
            "proto": "h2",
            "server_name": "vaultwarden.one4all.icu"
        }
    },
    "duration": 0.028404805,
    "status": 500,
    "err_id": "wlHcfBYQdfFZeGAY",
    "err_trace": ""
}

3. Caddy version:

v2.7.5 h1:HoysvZkLcN2xJExEepaFHK92Qgs7xAiCFydN5x5Hs6Q=

4. How I installed and ran Caddy:

Caddy is running as a container with docker.

a. System environment:

OS architecture

Linux srvone4all 5.4.0-1097-raspi #109-Ubuntu SMP PREEMPT Wed Oct 11 16:15:36 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux


NAME="Ubuntu"
VERSION="20.04.6 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.6 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

Docker version

Docker version 24.0.7, build afdd53b

b. Command:

Caddy is a service and it is build from a Dockerfile

docker compose up -d

c. Dockerfile:

FROM caddy:builder AS builder
RUN xcaddy build --with github.com/corazawaf/coraza-caddy@master

FROM caddy:alpine

COPY --from=builder /usr/bin/caddy /usr/bin/caddy
RUN set -eux; \
    apk add --no-cache libcap tzdata; \
    setcap cap_net_bind_service=ep /usr/bin/caddy; \
    addgroup -g 2023 -S www-caddy; \
    adduser -u 2023 -D -S -G www-caddy www-caddy; \
    chown -R www-caddy /data /var/log

USER www-caddy

WORKDIR /srv

CMD ["/usr/bin/caddy", "run", "--config", "/Caddyfile", "--adapter", "caddyfile"]

d. My complete Caddy config:

# coraza_waf first must be always included in your Caddyfile for Coraza module to work
{
	order coraza_waf first
	persist_config off
	log {
		level INFO
		output file /var/log/caddy/access.log
	}
	servers {
		timeouts {
			# sets timeouts for various actions
			idle 10s # timeout for idle connections
			read_body 10s # timeout for reading request body
			read_header 10s # timeout for reading request header
		}
		max_header_size 4KB # sets maximum header size for requests
	}
}

# Default server block that will respond with a "Not found" message for all requests to port 443
:443 {
	log
	respond "Not found" 404
}
# Default server block that will respond with a "Not found" message for all requests to port 80
:80 {
	log
	respond "Not found" 404
}
# Pour chacune de nos applications nous aurons des règles différentes à appliquer, si l'on souhaite traiter les faux positifs plus tard.
{$DOMAIN} {
	log
	coraza_waf {
		# On charge les paramètres globaux de coraza.
		include /ruleset/coraza.conf
		# On charge les paramètres CRS specifique à notre site.
		include /ruleset/vaultwarden/*.conf
		# On charge toutes les règles CRS que le WAF utilisera.
		include /ruleset/coreruleset/rules/*.conf
	}
	# Handle vaultwarden sends with file upload.
	request_body /api/sends/* {
		max_size 100MB
	}

	request_body {
		max_size 100KB
	}

	# Uncomment this if you want to get a cert via ACME (Let's Encrypt or ZeroSSL).
	tls {$EMAIL}

	encode gzip

	# Uncomment to improve security (WARNING: only use if you understand the implications!)
	# If you want to use FIDO2 WebAuthn, set X-Frame-Options to "SAMEORIGIN" or the Browser will block those requests
	# By default, Caddy set the following good security practice:
	#
	# By default, Vaultwarden actually handle a lot Web Header and caching, which is very nice!
	header {
		# Enable HTTP Strict Transport Security (HSTS)
		Strict-Transport-Security "max-age=15768000;"
		# Enable cross-site filter (XSS) and tell browser to block detected attacks
		X-XSS-Protection "1; mode=block"
		#Good Practice Security - Ensure X-Content-Type-Options header is configured and enabled
		Referrer-Policy "no-referrer"
		#Good Practice Security -  X-Content-Type-Options header is configured and enabled
		X-Content-Type-Options "nosniff"
		# Disallow the site to be rendered within a frame (clickjacking protection)
		X-Frame-Options "SAMEORIGIN"
		# Prevent search engines from indexing (optional)
		X-Robots-Tag "none"
		# Server name removing
		-Server
	}

	@insecureadmin {
		not remote_ip 192.168.1.0/24
		path /admin*
	}
	redir @insecureadmin /
	# Proxy everything to Rocket
	reverse_proxy vaultwarden:60278 {
		# Send the true remote IP to Rocket, so that vaultwarden can put this in the
		# log, so that crowdsec can ban the correct IP.
		header_up X-Real-IP {remote_host}
	}
}

unifi.one4all.icu {
	log
	@postinform {
		method POST
		path /inform
	}
	reverse_proxy @postinform unifi-controller:8080
	reverse_proxy unifi-controller:8443 {
		transport http {
			tls_insecure_skip_verify
		}
	}
	@insecureaccess {
		not remote_ip 192.168.1.0/24
	}
	respond @insecureaccess "Access Forbidden!" 403
}

5. Links to relevant resources:

I think it’s because you have two of them. Remove the second one.

Please run caddy fmt -o on your config, the indentation is very messy so it’s hard to read.

There’s no benefit to doing this at all. It doesn’t help security in any way.

1 Like

Hello Francis,

Thanks for the tips for formating Caddyfile :slight_smile:

I made an error in the Caddy configuration file (i edited the configuraiton file). I intended to set a default request body size limit of 100KB for all requests. Additionally, I wanted to specify that requests with the path /api/sends/* should have a larger request body size limit of 100MB.

Regards,

BBA

In that case you’ll need to use a negated path matcher for your second one so that they don’t both run on your API route.

@not-api not path /api/sends/*
request_body @not-api {
	max_size 100KB
}
1 Like