"Abort" snippet for non-local IPs not working

1. The problem I’m having:

I have many forwards. I want all of them to only allow local IPs (private_ranges). I tried it with a snippet and importing that one underneath my *.example.com, but it’s forwarding/allowing everything.

2. Error messages and/or full log output:

No error logs, since Caddy is just allowing everything. I can curl from a remote (public) IP and everything is allowed, even though it should be aborting non private_ranges

3. Caddy version:

v2.10.2

4. How I installed and ran Caddy:

Docker compose on Debian.

a. System environment:

Debian VM on Proxmox, running docker compose (v5.1.0)

b. Command:

N/A

c. Service/unit/compose file:

services:
  caddy:
    build: .
    container_name: caddy
    network_mode: host
    restart: unless-stopped
    volumes:
      - ./conf:/etc/caddy
      - ./site:/srv
      - ./caddy_data:/data
      - ./caddy_config:/config

d. My complete Caddy config:

{
	email email@example.com
	acme_dns transip {
		login my_username
		private_key /etc/caddy/my_key.pem
	}
}

(internal_only) {
    @not_private not remote_ip private_ranges
    abort @not_private
}

*.example.com {
	import internal_only

	@test host test.example.com
	handle @test{
		reverse_proxy 192.168.1.100:8880
	}
}

5. Links to relevant resources:

Putting it all in a route block seems to be working, for example:

{
	email email@example.com
	acme_dns transip {
		login my_username
		private_key /etc/caddy/my_key.pem
	}
}

(internal_only) {
    @not_private not remote_ip private_ranges
    abort @not_private
}

*.example.com {
	route {
		import internal_only

		@test host test.example.com
		handle @test{
			reverse_proxy 192.168.1.100:8880
		}
	}
}

I’m just not sure if this would be the best pratice…

handle has higher priority than abort, so your traffic will never reach it unless someone tries to access something other than the sites you listed.

I’m on my phone right now, but I’ll post a better approach to your problem once I’m back on my computer, sorry.

In the meantime, take a look at the directive order:

As timelordx said, handle is sorted above abort so that’s why it fails, but when you wrap it in a route it disables the directive sorting so it forces abort to be first and you get the behaviour you expect. Alternatively, you could make your snippet have a handle around the abort (apply the matcher on the handle) then since the handles are at the same nesting level with eachother they will act mutually exclusively and the first one which matches (in the order they appear) will execute.