What is the order of server parsing

1. Caddy version (caddy version):

2.1

2. How I run Caddy:

CaddyFile

a. System environment:

Ubuntu 16.04

3. The problem I’m having:

I need to resolve some uncertain domain to reverse proxy(no ssl required), the CaddyFile like this:

*.*.example.com:80 {
  encode zstd gzip
  templates
  file_server
  try_files {path} /index.html
  root * /web/{http.request.host.labels.2}/dist/{http.request.host.labels.3}
}

:80 {
  @extracthost {
    not header_regexp Host ^.*example.*$
  }
  reverse_proxy @extracthost http://localhost:3000
}

But the *.*.example.com:80 never worked
How do i change its parsing order?

PS: If I try to use an undeclared domain name to access, I will get an error

2020/06/16 17:16:02 http: panic serving 223.166.222.111:63424: runtime error: index out of range [-1]
goroutine 1971 [running]:
net/http.(*conn).serve.func1(0xc000a0bd60)
	net/http/server.go:1772 +0x139
panic(0x1700340, 0xc0011d6ec0)
	runtime/panic.go:975 +0x3e3
github.com/caddyserver/caddy/v2/modules/caddyhttp.addHTTPVarsToReplacer.func1(0xc000d3ab6d, 0x1a, 0x0, 0x0, 0x0)
	github.com/caddyserver/caddy/v2@v2.1.0-beta.1/modules/caddyhttp/replacer.go:180 +0x216f
github.com/caddyserver/caddy/v2.(*Replacer).Get(0xc0011a0640, 0xc000d3ab6d, 0x1a, 0x1, 0x1b, 0xc000ce1c01)
	github.com/caddyserver/caddy/v2@v2.1.0-beta.1/replacer.go:62 +0x77
github.com/caddyserver/caddy/v2.(*Replacer).replace(0xc0011a0640, 0xc000d3ab40, 0x48, 0x0, 0x0, 0x1, 0x0, 0xc0009eac80, 0x4, 0x0, ...)
	github.com/caddyserver/caddy/v2@v2.1.0-beta.1/replacer.go:164 +0x3a7
github.com/caddyserver/caddy/v2.(*Replacer).ReplaceAll(...)
	github.com/caddyserver/caddy/v2@v2.1.0-beta.1/replacer.go:101

I’m not sure what you mean by “never worked” or what you mean by “parsing order”. Can you specifically describe the behaviour you’re seeing and what you expect to see?

Thanks for pointing out that error with the labels placeholder. I’m not sure if there’s really anything we can do to fix it though. We could make it silently return an empty string, but that wouldn’t be particularly helpful in many cases, it would just hide the problem. Technically it’s the correct error to return, that the label index doesn’t exist. @matt you might have an opinion about that error.

@aker Thanks for the question. Could you file an issue on GitHub so I can look into it more? Sign in to GitHub · GitHub – be sure to link to this forum thread and include the most important information (config and errors) for good measure. Specifically, can you please add the specific steps to recreate it? (“try to use an undeclared domain name to access” isn’t specific enough – please give a curl command or something)

Also in the issue can you paste the output of caddy adapt for your config? Thanks!

If you have two server configurations, *.example.com:80 and :80, and try to access by xx.example.com,It will be parsed by: 80。I hope it can be parsed by *.example.com:80, I try to change their order, but never worked.

That is different than the panic you posted above. I’m not sure how to get the panic you are reporting.

But, the ordering issue may be fixed here in this commit today:

https://github.com/caddyserver/caddy/commit/32cafbb6309c8d78cc7e2f2a75def9c633944ef8

Yours was a bit of an edge case, but I guess this makes sense.

I’d still like to know how to get the panic you saw.

No problem!

I tried many ways,currently I changed it to this:

:80 {
  @extracthost {
    not header_regexp Host mokekeji\.com
  }

  @download {
    header_regexp Host ^download.*mokekeji\.com$
  }

  reverse_proxy @extracthost http://localhost:3000
  reverse_proxy @download http://localhost:3000
  encode zstd gzip
  file_server
  try_files {path} /index.html
  root * /data/web/{http.request.host.labels.2}/dist/{http.request.host.labels.3}
}

I cannot merge the two matchers because golang does not support negative lookahead,and caddy matcher does not support ‘or’ .

caddy adapt config output:

{"apps":{"http":{"servers":{"srv0":{"listen":[":80"],"routes":[{"handle":[{"handler":"vars","root":"/data/web/{http.request.host.labels.2}/dist/{http.request.host.labels.3}"}]},{"match":[{"file":{"try_files":["{http.request.uri.path}","/index.html"]}}],"handle":[{"handler":"rewrite","uri":"{http.matchers.file.relative}"}]},{"handle":[{"encodings":{"gzip":{},"zstd":{}},"handler":"encode"}]},{"match":[{"not":[{"header_regexp":{"Host":{"pattern":"mokekeji\\.com"}}}]}],"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"localhost:3000"}]}]},{"match":[{"header_regexp":{"Host":{"pattern":"^download.*mokekeji\\.com$"}}}],"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"localhost:3000"}]}]},{"handle":[{"handler":"file_server","hide":["Caddyfile"]}]}],"automatic_https":{"disable_redirects":true}}}}}

Nice to see the problem is fixed!

I commented a reverse proxy,then use any undeclared domain name to access the server, you will get this error.

:80 {
  @extracthost {
    not header_regexp Host mokekeji\.com
  }

  @download {
    header_regexp Host ^download.*mokekeji\.com$
  }

  #reverse_proxy @extracthost http://localhost:3000
  reverse_proxy @download http://localhost:3000
  encode zstd gzip
  file_server
  try_files {path} /index.html
  root * /data/web/{http.request.host.labels.2}/dist/{http.request.host.labels.3}
}

I think you could do something like this?

@proxiedHosts {
	expression !{host}.contains('mokekeji\.com') || {host}.matches('^download.*mokekeji\.com$')
}
reverse_proxy @proxiedHosts localhost:3000

Thanks, this is a different config from what you posted above. Indeed, with this config you can get a panic because the domains may not have labels 2 and 3. I’ll fix it so it won’t panic, but be aware that the placeholders will return empty string in that case.

Also if you’re using the latest from master or at least v2.1 beta 1, you can reduce those placeholders to {labels.2} and {labels.3}. We added additional shortcuts for those.

1 Like

There seems to be a syntax error, but I can’t find where

ERROR: \u003cinput\u003e:1:58: Syntax error: token recognition error at: ''mokekeji\\.'\n | !caddyPlaceholder(request, \"http.request.host\").contains('mokekeji\\.com') || caddyPlaceholder(request, \"http.request.host\").matches('^download.*mokekeji\\.com$')\n | .........................................................^\nERROR: \u003cinput\u003e:1:72: Syntax error: mismatched input '') || caddyPlaceholder(request, \"http.request.host\").matches('' expecting ')'\n | !caddyPlaceholder(request, \"http.request.host\").contains('mokekeji\\.com') || caddyPlaceholder(request, \"http.request.host\").matches('^download.*mokekeji\\.com$')\n | .......................................................................^\nERROR: \u003cinput\u003e:1:134: Syntax error: token recognition error at: '^'\n | !caddyPlaceholder(request, \"http.request.host\").contains('mokekeji\\.com') || caddyPlaceholder(request, \"http.request.host\").matches('^download.*mokekeji\\.com$')\n | .....................................................................................................................................^\nERROR: \u003cinput\u003e:1:153: Syntax error: token recognition error at: '\\'\n | !caddyPlaceholder(request, \"http.request.host\").contains('mokekeji\\.com') || caddyPlaceholder(request, \"http.request.host\").matches('^download.*mokekeji\\.com$')\n | ........................................................................................................................................................^\nERROR: \u003cinput\u003e:1:158: Syntax error: token recognition error at: '$'\n | !caddyPlaceholder(request, \"http.request.host\").contains('mokekeji\\.com') || caddyPlaceholder(request, \"http.request.host\").matches('^download.*mokekeji\\.com$')\n | .............................................................................................................................................................^\nERROR: \u003cinput\u003e:1:159: Syntax error: token recognition error at: '')'\n | !caddyPlaceholder(request, \"http.request.host\").contains('mokekeji\\.com') || caddyPlaceholder(request, \"http.request.host\").matches('^download.*mokekeji\\.com$')\n | ..............................................................................................................................................................^"}

Glad to find the reason

Ah, interesting. Seems like CEL expressions require you to prefix strings with r to tell it it’s a raw string, so it doesn’t try to interpret escape sequences, so that the escape happens by the regexp parsing instead.

This seems to validate (the \ on the first one didn’t need to be there because it’s not a regexp but rather a fast substring match):

@proxiedHosts {
        expression !{host}.contains('mokekeji.com') || {host}.matches(r'^download.*mokekeji\.com$')
}
reverse_proxy @proxiedHosts localhost:3000
1 Like

No errors now,however, it still triggers the error that the labels cannot be parsed. It seems that it needs to wait for the ordering problem to be fixed or the errors parsed by the lables to be resolved before it can run correctly.

The ordering problem is fixed by this commit as Matt already said:

https://github.com/caddyserver/caddy/commit/32cafbb6309c8d78cc7e2f2a75def9c633944ef8

You can grab the build artifact from here: httpcaddyfile: Fix ordering of catch-all site blocks · caddyserver/caddy@32cafbb · GitHub

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