Configure allow and deny in one match

1. Caddy version (caddy version):

./caddy version
v2.5.0 h1:eRHzZ4l3X6Ag3kUt8nj5IxATprhqKq/wToP7OHlXWA0=

2. How I run Caddy:

./caddy run

a. System environment:

I call it via cli

b. Command:

# terminal 1
./caddy run

# terminal 2
curl localhost:8081/config/ -H "Content-Type: application/json" -d @hello-world.json
curl localhost:8081/config/apps/http/servers/example2 -H "Content-Type: application/json" -d @second-http-server.json

# deny call
curl -vH 'X-Forwarded-For: 10.2.4.5' localhost:2016/print-headers.tmpl

# allow call
curl -vH 'X-Forwarded-For: 127.0.0.1' localhost:2016/print-headers.tmpl

c. Service/unit/compose file:

Use cli

d. My complete Caddyfile or JSON config:

# Caddyfile
{
	debug
	admin 127.0.0.1:8081
}

hello-world.json:

{
  "admin": {
    "listen": "127.0.0.1:8081"
  },
  "apps": {
    "http": {
      "http_port": 8081,
      "https_port": 8443,
      "grace_period": "30m",
      "servers": {
        "example": {
          "listen": [":2015"],
          "routes": [
            {
              "handle": [
                {
                  "@id": "stat-resp",
                  "handler": "static_response",
                  "body": "I can do hard things."
                }
              ]
            }
          ]
        }
      }
    }
  },
  "logging": {
    "logs": {
      "default": {
        "level": "DEBUG"
      },
      "myaccesslogger": {
        "writer": {
          "output": "stdout"
        },
        "encoder": {
          "format": "json"
        }
      }
    }
  }
}

second-http-server.json

{
  "listen": [":2016"],
  "routes": [
    {
      "match": [
        {
          "path": ["*.tmpl"],
          "not": [
            {
              "remote_ip": {
                "ranges": ["127.0.0.1"],
                "forwarded": true
              }
            }
          ]
        }
      ],
      "handle": [
        {
          "handler": "static_response",
          "status_code": 401
        }
      ]
    },
    {
      "match": [
        {
          "path": ["*.tmpl"]
        }
      ],
      "handle": [
        { "handler": "encode" },
        { "handler": "templates" },
        {
          "handler": "headers",
          "response": {
            "set": {
              "Content-Type": ["text/plain; charset=utf-8"]
            }
          }
        },
        { "handler": "file_server" }
      ]
    }
  ],
  "logs": {
    "default_logger_name": "myaccesslogger"
  }
}

3. The problem I’m having:

I would like to use the remote_ip check and the handler for allow/and deny in one match block, because the config above looks quite verbose.
Is this possible?

4. Error messages and/or full log output:

# deny call
2022/04/26 11:54:37.747	ERROR	http.log.access.myaccesslogger	handled request	{"request": {"remote_ip": "127.0.0.1", "remote_port": "54796", "proto": "HTTP/1.1", "method": "GET", "host": "localhost:2016", "uri": "/print-headers.tmpl", "headers": {"User-Agent": ["curl/7.68.0"], "Accept": ["*/*"], "X-Forwarded-For": ["10.2.4.5"]}}, "user_id": "", "duration": 0.000021388, "size": 0, "status": 401, "resp_headers": {"Server": ["Caddy"], "Content-Type": []}}
{"level":"error","ts":1650974077.7472606,"logger":"http.log.access.myaccesslogger","msg":"handled request","request":{"remote_ip":"127.0.0.1","remote_port":"54796","proto":"HTTP/1.1","method":"GET","host":"localhost:2016","uri":"/print-headers.tmpl","headers":{"User-Agent":["curl/7.68.0"],"Accept":["*/*"],"X-Forwarded-For":["10.2.4.5"]}},"user_id":"","duration":0.000021388,"size":0,"status":401,"resp_headers":{"Server":["Caddy"],"Content-Type":[]}}


# allow call
2022/04/26 11:45:50.163	DEBUG	http.handlers.file_server	sanitized path join	{"site_root": ".", "request_path": "/print-headers.tmpl", "result": "print-headers.tmpl"}
2022/04/26 11:45:50.163	DEBUG	http.handlers.file_server	opening file	{"filename": "print-headers.tmpl"}
2022/04/26 11:45:50.164	INFO	http.log.access.myaccesslogger	handled request	{"request": {"remote_ip": "127.0.0.1", "remote_port": "54794", "proto": "HTTP/1.1", "method": "GET", "host": "localhost:2016", "uri": "/print-headers.tmpl", "headers": {"User-Agent": ["curl/7.68.0"], "Accept": ["*/*"], "X-Forwarded-For": ["127.0.0.1"]}}, "user_id": "", "duration": 0.000569331, "size": 218, "status": 200, "resp_headers": {"Content-Length": ["218"], "Server": ["Caddy"], "Content-Type": ["text/plain; charset=utf-8"]}}
{"level":"info","ts":1650973550.1643727,"logger":"http.log.access.myaccesslogger","msg":"handled request","request":{"remote_ip":"127.0.0.1","remote_port":"54794","proto":"HTTP/1.1","method":"GET","host":"localhost:2016","uri":"/print-headers.tmpl","headers":{"User-Agent":["curl/7.68.0"],"Accept":["*/*"],"X-Forwarded-For":["127.0.0.1"]}},"user_id":"","duration":0.000569331,"size":218,"status":200,"resp_headers":{"Server":["Caddy"],"Content-Type":["text/plain; charset=utf-8"],"Content-Length":["218"]}}

5. What I already tried:

I tried to combine the handler in the same match block but this had not the wanted behavior.

6. Links to relevant resources:

I don’t understand what you mean. That config looks like the simplest possible way, to me.

okay. thanks for the confirmation.