Order / processing of handle directives unclear

1. The problem I’m having:

I have a config that uses a snippet to handle some blocked clients, but they don’t get blocked by Caddy. I think it has to do with using handle directives and order / processing of the config file, but I honestly can’t make heads or tails of it anymore. I tried adding the abort in the last handle {} directive too, but no matter what, the clients are not blocked/aborted. I can see in the logs that the remote_ip / client_ip matches the specified ip in the snippet, but the requests just get passed through.

Edit: actually I think they did start getting blocked when I added the abort @banned directive also into the last handle {} block. I simply made the false assumption they were not blocked because requests still got logged (but they no longer had a response status code etc I noticed later).

I am just wondering now, do I need to add the abort @banned directive into every handle[_path] {} block?

2. Error messages and/or full log output:

3. Caddy version:

v2.7.6 h1:w0NymbG2m9PcvKWsrXO6EEkY9Ru4FJK8uQbYcev1p3A=

4. How I installed and ran Caddy:

a. System environment:

Ubuntu 23.10
systemd 253 (253.5-1ubuntu6.1)

b. Command:

PASTE OVER THIS, BETWEEN THE ``` LINES.
Please use the preview pane to ensure it looks nice.

c. Service/unit/compose file:

PASTE OVER THIS, BETWEEN THE ``` LINES.
Please use the preview pane to ensure it looks nice.

d. My complete Caddy config:

(banned) {
  @banned {
    remote_ip 1.2.3.4
    remote_ip 5.6.7.8
  }
}

domain.tld {
  root * /path/to/root
  import banned
  abort @banned
  handle_path /sub/* {
    redir {uri} 301
  }
  @phpfile path *.php *.php/*
  handle @phpfile {
    error 403
  }
  @exists file
  @staticFiles path *.jpg *.jpeg *.js *.css *.png *.woff *.woff2 *.otf *.ttf *.gif *.svg *.webp
  handle @exists {
    header @staticFiles Cache-Control "public, max-age=604800, s-maxage=86400, stale-while-revalidate=3600, must-revalidate"
    header ?access-control-allow-origin *
    header ?access-control-allow-methods "GET"
    file_server
  }
  @skipvarnish path /admin* /api/*
  handle @skipvarnish {
    reverse_proxy {
      to http://localhost:8080
      header_up x-real-ip {remote_host}
      header_up x-request-id {http.request.uuid}
      transport http {
        dial_timeout 2s
        keepalive 60s
      }
    }
  }
  handle {
    reverse_proxy {
      to http://10.0.0.10:6081
      header_up x-real-ip {remote_host}
      header_up x-request-id {http.request.uuid}
      transport http {
        dial_timeout 2s
        keepalive 60s
      }
    }
  }
}

5. Links to relevant resources:

The sorting algorithm for directives is explained here:

abort has a lower order than handle, so it will be sorted below those.

handle blocks are mutually exclusive from eachother, only the first matching one will run. You could put your abort inside a handle which has your matcher.

The tricky bit though is that handle with path matchers will get sorted above those with other kinds of matchers, which means since your @banned matcher has remote_ip it will end up running after some of your other handles.

One thing you could do is override the order of abort to be before handle using the order global option. That’s a valid thing to do for your case to make sure a connection is aborted before any other kind of handling. Or you could wrap your whole thing in a route to make the order things appear in your Caddyfile be the order it runs in, but I tend not to like that because it adds a level of indentation. Or yeah, you could put your abort inside each handle :man_shrugging:

1 Like

Just to be clear, I basically should put this at the top of my Caddyfile?

{
  order abort before handle
}
1 Like

Yeah, should do for your usecase.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.