Caddy Layer4 with Authentik LDAP Output - Not connecting / routing

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 :face_with_raised_eyebrow:.

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

I see Caddy is running in a container. Is Authentik also running a container? Is it the same container as Caddy? I see you’re trying to proxy to localhost-IPv6, which means this container.

Podman is a bit different than Docker.

It’s 2 separate Containers.

Both Containers are in the same Pod.

This means that they share the Network Namespace.
Basically Caddy is the “Master” to which the other Containers are mapped. But every container-internal port of every Container is directly accessible through all containers within the Pod.

I use that Directive (slightly different) for the “normal” Caddy Layer7 Proxy everywhere and it works without Issues there:

reverse_proxy http://[::1]:{$APPLICATION_PORT}

@Mohammed90
Any Update?

No clue. It appears to be a Podman network problem, not a Caddy config issue. I’m not familiar enough with Podman.

How can it be a Podman Network Issue if it works correctly with the “normal” (non Layer-4) Caddy using exactly the same Principle though ?

I recall there were some Podman Networking Issues related to some weird UDP Packages and Broadcasting etc in some Scenario.

But I’m not aware of anything TCP related.

The connection apparently doesn’t reach Caddy, even though Caddy is listening on the port.

Looks like I’ll need to use traefik for this then.

That’s really a shame & ironic since I was moving from traefik + ~20 Services to caddy + 1 Service so that it’s more Modular, Scalable & Independent.

Now I need to head back to traefik and/or have a Hybrid caddy + traefik Setup …

I’m simply asking for evidence that the connection hit Caddy it all, even if not proxied. That is typically logged, especially since you have debug enabled. You shared a single log line that just says Caddy is listening on the port.

The config looks fine as-is. You can check wireshark to see where things fall short.

1 Like

I hope I will have some Time to come back to this Topic soon … Right now, whether it’s with traefik or with caddy, it appears that nothing is happening. It’s NOT a Firewall Issue, that should be fixed.