1. The problem I’m having:
I built a custom Caddy Docker Container with xcaddy
to include Layer4 Capabilities.
But obviously the LDAP Server (running as Authentik LDAP Output) cannot be reached at all.
Neither from OPNSense Router (which I was using to integrate with Authentik), neither from any GNU/Linux Client.
Running:
ldapsearch -vvv -x -H ldaps://[2aXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX] -b "<LDAP_BASEDN>" -D "<LDAP_BINDDN>" -w "<LDAP_BINDPASSWORD>" -s sub
Results in:
ldap_initialize( ldaps://[2aXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX]:636/??base )
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
2. Error messages and/or full log output:
Well, there isn’t much to go by at all in the Logs even with debug
enabled .
The only relevant Line I can see at startup is this:
Jul 13 18:51:50 podmanserver16 authentik-caddy[1847561]: {"level":"debug","ts":1752425510.4361851,"logger":"layer4","msg":"listening","address":"tcp/[::1]:636"}
After that, no match at all for either Port 636
(exposed on LAN Network) nor Port 3389
(Internal Podman Pod Network). I even tried to disable the SNI matching thinking that it was at fault, but unfortunately, even after disabling SNI matching, it seems like Caddy is just not routing the LDAP Requests.
HTTP(s) Requests are working fine as before.
3. Caddy version:
2.10.0
4. How I installed and ran Caddy:
Dockerfile:
ARG CADDY_VERSION=2
FROM caddy:${CADDY_VERSION}-builder AS builder
RUN xcaddy build \
--with github.com/mholt/caddy-l4
FROM caddy:${CADDY_VERSION}-alpine
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
a. System environment:
- Fedora 42 GNU/Linux AMD64
- Podman 5.5.2
- Kernel 6.15.5-200.fc42.x86_64
b. Command:
As in Dockerfile:
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
c. Service/unit/compose file:
Podman Quadlet Configuration authentik-caddy.container
:
[Service]
Restart=always
[Container]
ContainerName=authentik-caddy
Pod=authentik.pod
StartWithPod=true
Environment=CADDY_DOCKER_CADDYFILE_PATH=/etc/caddy/Caddyfile
EnvironmentFile=.env.caddy
# Image=caddy:latest
Image=caddy-layer4:alpine-latest
Pull=missing
NoNewPrivileges=true
AddCapability=CAP_NET_RAW CAP_NET_BIND_SERVICE
Volume=./Caddyfile:/etc/caddy/Caddyfile:ro,z
Volume=/home/podman/containers/data/authentik/caddy:/data/caddy:z
Volume=/home/podman/containers/log/authentik/caddy:/var/log:z
Volume=/home/podman/containers/config/authentik/caddy:/config/caddy:z
Volume=/home/podman/containers/certificates/letsencrypt:/certificates:ro,z
d. My complete Caddy config:
# Example and Guide
# https://caddyserver.com/docs/caddyfile/options
# General Options
{
# (Optional) Debug Mode
debug
# Disable Admin API
admin off
# TLS Options
# (Optional) Disable Certificates Management (only if SSL/TLS Certificates are managed by certbot or other external Tools)
auto_https disable_certs
# (Optional) Default SNI
default_sni {$APPLICATION_HOSTNAME}
layer4 {
tcp/[::1]:636 {
# tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem}
#log {
# output file /var/log/{$APPLICATION_HOSTNAME_ALTERNATE}/ldap/access.json {
# roll_size 100MiB
# roll_keep 5000
# roll_keep_for 720h
# roll_uncompressed
#}
#
# format json
#}
# @secure tls sni {$APPLICATION_HOSTNAME}
# route @secure {
# proxy [::1]:636
# }
# @matchldap {
# tls sni {$APPLICATION_HOSTNAME}
# }
# Match SNI
# route @matchldap {
# Don't match any specific SNI
route {
# tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem}
tls
# log {
# output file /var/log/{$APPLICATION_HOSTNAME_ALTERNATE}/ldap/access.json {
# roll_size 100MiB
# roll_keep 5000
# roll_keep_for 720h
# roll_uncompressed
# }
# format json
#}
proxy tcp/[::1]:3389 {
}
}
}
}
}
# Caddy API Endpoint
localhost {
reverse_proxy /api/* localhost:9001
}
# Main Domain
# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required
{$APPLICATION_HOSTNAME} {
tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem}
log {
output file /var/log/{$APPLICATION_HOSTNAME}/http/access.json {
roll_size 100MiB
roll_keep 5000
roll_keep_for 720h
roll_uncompressed
}
format json
}
reverse_proxy http://[::1]:{$APPLICATION_PORT}
}
# Alternate Domain (HTTPS)
# (Optional) Only if SSL/TLS Certificates are managed by certbot or other external Tools and Custom Logging is required
{$APPLICATION_HOSTNAME_ALTERNATE} {
tls /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_CERT_FILE:fullchain.pem} /certificates/{$APPLICATION_CERTIFICATE_DOMAIN}/{$APPLICATION_CERTIFICATE_KEY_FILE:privkey.pem}
log {
output file /var/log/{$APPLICATION_HOSTNAME_ALTERNATE}/http/access.json {
roll_size 100MiB
roll_keep 5000
roll_keep_for 720h
roll_uncompressed
}
format json
}
reverse_proxy http://[::1]:{$APPLICATION_PORT}
}
5. Links to relevant resources:
At first I could notice that every Request on Port 636 (LDAP with TLS Termination, via Caddy Layer4 in this Case) was blocked by the Firewall (as default on Fedora GNU/Linux).
However, even after adding & allowing the Service in the Firewall, it still will not work, despite this Time being able to see that I can reach some Service:
nmap -6 -p 636,3389 2aXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-07-13 18:15 CEST
Nmap scan report for 2aXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
Host is up (0.00038s latency).
PORT STATE SERVICE
636/tcp open ldapssl
3389/tcp filtered ms-wbt-server