caddy: Directive "log - output file" on one site address causes log output from another site address to dump to the console

caddy 2.5.1-1 on Arch Linux

From https://caddyserver.com/docs/caddyfile/concepts :

If you specify a hostname, only requests with a matching Host header will be honored. In other words, if the site address is localhost, then Caddy will not match requests to 127.0.0.1.

{
	admin unix//run/caddy/admin.socket
}
http://localhost {
	root * /home/http/htdocs/
	file_server browse
}
http://10.0.0.2 {
	root * /home/http/htdocs/public/
	file_server browse
	log {
		output file /var/log/caddy/accesslog {
			roll_size 10MiB
			roll_keep 4
		}
		format console {
			time_format rfc3339
			duration_format string
		}
}

Then, sudo caddy start --config /etc/caddy/Caddyfile and point the browser to http://127.0.0.1 . The browser will display a blank page, and the console from which “caddy start” was run will spew logging output for ..., "host": "127.0.0.1", ...!

Logging for the other sites, http://localhost and http://10.0.0.2, works as anticipated.

Log output to the console is not expected and not wanted.

Adding a gratuitous

http://127.0.0.1 {
}

to the Caddyfile changes "logs":{"logger_names":{"10.44.0.20":"log0"},"skip_hosts":["localhost"]} to "logs":{"logger_names":{"10.44.0.20":"log0"},"skip_hosts":["localhost","127.0.0.1"]} in the json config structure, which is an effective workaround.

But still, should that workaround be necessary? Or simply documented?

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 18 (11 by maintainers)

Most upvoted comments

Would that have to be both a skip_log handler and a logger_names handler?

No, logger_names is not a handler (a handler is an HTTP middleware).

You cannot “skip” a site hostname or site IP address when you do not know that it exists

Actually that’s exactly what I’m suggesting we do, i.e. add the skip_log handler to the end of the HTTP routes, so that if no other HTTP route matches (i.e. by hostname like localhost or whatever), it falls through and hits skip_log.

So basically, taking this Caddyfile:

http://10.0.0.2 {
    log
    respond "ip"
}

http://localhost {
    respond "localhost"
}

which adapts to this JSON

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [
            ":80"
          ],
          "routes": [
            {
              "match": [
                {
                  "host": [
                    "10.0.0.2"
                  ]
                }
              ],
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "body": "ip",
                          "handler": "static_response"
                        }
                      ]
                    }
                  ]
                }
              ],
              "terminal": true
            },
            {
              "match": [
                {
                  "host": [
                    "localhost"
                  ]
                }
              ],
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "body": "localhost",
                          "handler": "static_response"
                        }
                      ]
                    }
                  ]
                }
              ],
              "terminal": true
            }
          ],
          "logs": {
            "skip_hosts": [
              "localhost"
            ]
          }
        }
      }
    }
  }
}

I would make this change to the generated output (scroll down):

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [
            ":80"
          ],
          "routes": [
            {
              "match": [
                {
                  "host": [
                    "10.0.0.2"
                  ]
                }
              ],
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "body": "ip",
                          "handler": "static_response"
                        }
                      ]
                    }
                  ]
                }
              ],
              "terminal": true
            },
            {
              "match": [
                {
                  "host": [
                    "localhost"
                  ]
                }
              ],
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "body": "localhost",
                          "handler": "static_response"
                        }
                      ]
                    }
                  ]
                }
              ],
              "terminal": true
-            }
+            },
+            {
+              "handle": [
+                {
+                  "handler": "skip_log",
+                }
+              ]
+            }
          ],
          "logs": {
            "skip_hosts": [
              "localhost"
            ]
          }
        }
      }
    }
  }
}

Since the localhost and 10.0.0.2 routes are "terminal": true, they prevent skip_log from happening, but any not-explicitly-configured hosts will have their logs skipped.

Effectively, the bind directive is an essential directive for any site definition!

Not really. Most users actually want to bind to all interfaces. Like if you want to accept traffic from internal services running on the same machine, etc.

You can use the default_bind global option (recently added) to avoid needing to write it in each of your sites, if you need it.

This is not actually documented

You’re right, we should document it in the site addresses section to mention the address is not the bind/listener. They are different things. The address produces a request matcher (which in turn affects whether automatic HTTPS triggers, and affects what the logger host will be, etc).

And the bind directive does not even allow defining the port for the site!

Yeah, that’s not its job. The site address does the port part. The bind does the IP interface part.

It appears to me that someone did not really think this interface/address/domain/host/port thing all the way through.

No, we have, this is intended.

Caddy, then, has this awkward characteristic of requiring the same site address to be defined in two different places, even though one site address should be inferred from the other site address.

Like I said, the bind address and the domain/site address are not the same thing, and we cannot assume that they are the same thing. That’s not a safe assumption to make.

@mholt Thanks Matt. While the Caddy configuration file tends to be finicky, I do have a working configuration now. Any improvements you are able to provide will add robustness and avoid confusing surprises for new users.