Abort undefined subdomains when using wildcards and forward authorization

1. The problem I’m having:

I use caddy with wildcards and Authelia. I want to modify my setup so if a subdomain is not defined, it is aborted. However, when I do so, Authelia still requires authorization before the abort is processed.

My Caddyfile currently looks like this:

auth.endpoint.internal {
    reverse_proxy authelia:9091
}


*.endpoint.internal {
    forward_auth authelia:9091 {
        uri /api/verify?rd=https://auth.endpoint.internal/
        copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
    }

    @srv1 host srv1.endpoint.internal
    handle @srv1 {
        respond "You are here"
    }

    handle {
        abort
    }
}

Navigating to srv1.endpoint.internal redirects me to Authelia as expected.
However, attempting to navigate to other endpoints that are not defined (such as foo.endpoint.internal) also redirects me to Authelia. I want these “undefined” endpoints to result in an abort as well.

# endpoint defined in caddyfile, should respond
> curl 'https://srv1.endpoint.internal'
<a href="https://auth.endpoint.internal/?rd=https%3A%2F%2Fsrv1.endpoint.internal%2F&amp;rm=GET">302 Found</a>

# endpoint not defined in caddyfile, should abort
> curl 'https://foo.endpoint.internal'
<a href="https://auth.endpoint.internal/?rd=https%3A%2F%2Ffoo.endpoint.internal%2F&amp;rm=GET">302 Found</a>

If I remove the Authelia configuration from the Caddyfile:

*.endpoint.internal {
    @srv1 host srv1.endpoint.internal
    handle @srv1 {
        respond "You are here"
    }

    handle {
        abort
    }
}

I get the expected behavior - srv1 returns a response, while any other endpoints get aborted.

# endpoint defined in caddyfile, should respond
> curl 'https://srv1.endpoint.internal'
You are here

# endpoint not defined in caddyfile, should abort
> curl 'https://foo.endpoint.internal'
curl: (92) HTTP/2 stream 1 reset by server (error 0x2 INTERNAL_ERROR)

How can I achieve this behavior while still using forward_auth and Authelia?

3. Caddy version:

v2.11.2 h1:iOlpsSiSKqEW+SIXrcZsZ/NO74SzB/ycqqvAIEfIm64=

4. How I installed and ran Caddy:

a. System environment:

Arch Linux x86_64 (Linux 6.19.11-arch1-1)
Docker version 29.4.0, build 9d7ad9ff18
Docker Compose version 5.1.3
SystemD 260.1-1-arch

b. Command:

docker compose up -d

c. Service/unit/compose file:

services:
  caddy:
    image: caddy
    container_name: caddy
    ports:
      - 80:80
      - 443:443
      - 443:443/udp
    volumes:
      - /data/Caddyfile:/etc/caddy/Caddyfile
  authelia:
    image: authelia/authelia:latest
    container_name: authelia
    volumes:
      - /data/authelia:/config

With Caddy 2.10.0 and newer, you can do this:

auth.endpoint.internal {
    reverse_proxy authelia:9091
}

*.endpoint.internal {
    abort
}

srv1.endpoint.internal {

   // your SRV1 stuff
}
auth.endpoint.internal {
    reverse_proxy authelia:9091
}

*.endpoint.internal {
    @srv1 host srv1.endpoint.internal
    handle @srv1 {
        forward_auth authelia:9091 {
            uri /api/verify?rd=https://auth.endpoint.internal/
            copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
        }
        respond "You are here"
    }

    handle {
        abort
    }
}

Here you go try this out and see if it work for you. I starting understand caddy language.

you can verify and test

curl -I https://srv1.endpoint.internal # 302 to Authelia
curl -I https://foo.endpoint.internal # connection reset / aborted

Thanks for the help. I ended up also putting the forward_auth declaration in a named route and using invoke so I don’t have to repeat the forward_auth declaration.

auth.endpoint.internal {
    reverse_proxy authelia:9091
}

&(authelia) {
    forward_auth authelia:9091 {
        uri /api/verify?rd=https://auth.endpoint.internal/
        copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
    }
}


*.endpoint.internal {
    abort
}

srv1.endpoint.internal {
    invoke authelia
    respond "you are here"
}

That awesome you got it great work

If you want to take it a step further and also drop HTTP requests for undefined sites, you could do something like this:

{
	auto_https disable_redirects
}

auth.endpoint.internal {
    reverse_proxy authelia:9091
}

&(authelia) {
    forward_auth authelia:9091 {
        uri /api/verify?rd=https://auth.endpoint.internal/
        copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
    }
}

*.endpoint.internal {
    abort
}

srv1.endpoint.internal {
    invoke authelia
    respond "you are here"
}

http://srv1.endpoint.internal {
	redir https://srv1.endpoint.internal{uri} 308
}

http:// {
	abort
}

The only site left with HTTP, for HTTP-to-HTTPS redirect, is srv1.endpoint.internal. Everything else is HTTPS-only or dropped.

Some details here: