1. The problem I’m having:
Hello everyone
This is my first post, so I hope I fill out the template correctly.
I have several services configured at home on a Raspi 4 through a Cloudflare tunnel that are working correctly. I’ve decided to set up a bastioned Raspi 3 where Caddy receives tunnel requests and acts as a reverse proxy for Raspi 4.
This is how the flow would work:
I use the Cloudflare tunnel URL → Caddy as a reverse proxy (Raspi 3) → services (Raspi 4).
On Raspi 4, I’ve generated some self-signed certificates that I use for HTTPS services. The CN is 192.168.8.20.
I can only get it to work with the “tls_insecure_skip_verify” directive.
I’ve read the Caddy documentation and think I should establish the trust relationship by copying the public key, but it’s not clear to me who should trust whom or where to store the key.
The ultimate goal is caddy + coraza + crowdsec, which is why the Dockerfile includes these modules. However, I’m testing slowly, which is why docker-compose only includes the caddy part.
Thank you very much in advance, and I hope I’ve explained myself well.
2. Error messages and/or full log output:
caddy | {"level":"debug","ts":1754002882.6457455,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"192.168.8.20:8443","duration":0.018820018,"request":{"remote_ip":"172.19.0.1","remote_port":"36880","client_ip":"172.19.0.1","proto":"HTTP/1.1","method":"GET","host":"bvw.enunlugarignotoeinefable.com","uri":"/favicon.ico","headers":{"Cf-Warp-Tag-Id":["b10ccddf-d637-4d45-98ad-4e6efcb3ff28"],"Cf-Connecting-Ip":["79.116.55.196"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Sec-Ch-Ua-Platform":["\"Android\""],"Accept-Language":["es-ES,es;q=0.9"],"Sec-Ch-Ua-Mobile":["?1"],"Via":["1.1 Caddy"],"Sec-Ch-Ua":["\"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\", \"Google Chrome\";v=\"138\""],"Cf-Ray":["9680b7a04bc09931-MAD"],"X-Forwarded-For":["172.19.0.1"],"Accept":["image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"],"Cdn-Loop":["cloudflare; loops=1"],"Referer":["https://bvw.enunlugarignotoeinefable.com/"],"X-Forwarded-Host":["bvw.enunlugarignotoeinefable.com"],"Sec-Fetch-Site":["same-origin"],"Cf-Ipcountry":["ES"],"Sec-Fetch-Mode":["no-cors"],"X-Forwarded-Proto":["https"],"Save-Data":["on"],"User-Agent":["Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36"],"Priority":["u=1, i"],"Sec-Fetch-Dest":["image"],"Accept-Encoding":["gzip, br"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"","server_name":"bvw.enunlugarignotoeinefable.com"}},"error":"tls: failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead"}
caddy | {"level":"error","ts":1754002882.6465626,"logger":"http.log.error.log1","msg":"tls: failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead","request":{"remote_ip":"172.19.0.1","remote_port":"36880","client_ip":"172.19.0.1","proto":"HTTP/1.1","method":"GET","host":"bvw.enunlugarignotoeinefable.com","uri":"/favicon.ico","headers":{"User-Agent":["Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36"],"Cf-Warp-Tag-Id":["b10ccddf-d637-4d45-98ad-4e6efcb3ff28"],"Cf-Ipcountry":["ES"],"X-Forwarded-Proto":["https"],"Sec-Ch-Ua-Platform":["\"Android\""],"Priority":["u=1, i"],"Sec-Ch-Ua-Mobile":["?1"],"Sec-Fetch-Site":["same-origin"],"Cdn-Loop":["cloudflare; loops=1"],"Sec-Ch-Ua":["\"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\", \"Google Chrome\";v=\"138\""],"Sec-Fetch-Mode":["no-cors"],"X-Forwarded-For":["79.116.55.196"],"Sec-Fetch-Dest":["image"],"Cf-Connecting-Ip":["79.116.55.196"],"Save-Data":["on"],"Accept":["image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"],"Accept-Language":["es-ES,es;q=0.9"],"Accept-Encoding":["gzip, br"],"Connection":["keep-alive"],"Referer":["https://bvw.enunlugarignotoeinefable.com/"],"X-Forwarded-Host":["bvw.enunlugarignotoeinefable.com"],"Cf-Ray":["9680b7a04bc09931-MAD"],"Cf-Visitor":["{\"scheme\":\"https\"}"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"","server_name":"bvw.enunlugarignotoeinefable.com"}},"duration":0.019425487,"status":502,"err_id":"fvu8nfqgk","err_trace":"reverseproxy.statusError (reverseproxy.go:1390)"}
3. Caddy version:
2.10.0
4. How I installed and ran Caddy:
a. System environment:
Raspberry pi 3B
Raspbian x64 Debian version, 12 (bookworm)
b. Command:
sudo docker compose up --build to see the output
sudo docker compose up -d when everyting works
c. Service/unit/compose file:
Dockerfile
FROM caddy:2.10.0-builder AS builder
RUN xcaddy build \
--with github.com/corazawaf/coraza-caddy/v2@latest \
--with github.com/hslatman/caddy-crowdsec-bouncer/http@main \
--with github.com/hslatman/caddy-crowdsec-bouncer/appsec@main \
--with github.com/hslatman/caddy-crowdsec-bouncer/layer4@main
FROM caddy:2.10.0
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
docker-compose.yml
services:
caddy:
build:
context: .
dockerfile: Dockerfile
container_name: caddy
restart: unless-stopped
cap_add:
- NET_ADMIN
ports:
- 80:80
- 443:443
# - 443:443/udp
- 8123:8123
- 8443:8443
- 4080:4080
volumes:
- $DOCKERDIR/caddy/log:/var/log
- $DOCKERDIR/caddy/ruleset:/ruleset
- $DOCKERDIR/caddy/Caddyfile:/etc/caddy/Caddyfile
- $DOCKERDIR/caddy/data:/data
- $DOCKERDIR/caddy/config:/config
d. My complete Caddy config:
{
#auto_https off
# Ponemos el log de debug (crowsec usa los log para detectar anomalías)
log {
level DEBUG
}
#Habilitamos coraza
order coraza_waf first
#Habilitamos y configuramos crowdsec
crowdsec {
api_url http://localhost:8080
api_key <api_key>
ticker_interval 15s
appsec_url http://localhost:7422
disable_streaming
#enable_hard_fails
}
}
#Configuración de reserve proxy (esto incluye la configuración para la inspección de coraza)
#VaultWarden
https://bvw.enunlugarignotoeinefable.com {
tls internal
# coraza_waf {
# load_owasp_crs
# directives `
# Include /ruleset/coraza.conf
# Include @owasp_crs/*.conf
# SecRuleEngine On
# `
# }
reverse_proxy https://192.168.8.20:8443 {
# transport http {
# tls_insecure_skip_verify
# }
}
log {
output file /var/log/caddy/vaultwarden.log
}
}