Debian Buster from the command line for testing as root.
b. Command:
./caddy run -config Caddyfile
c. Service/unit/compose file:
d. My complete Caddyfile or JSON config:
{
debug
}
dev3.foo.com {
log {
output stdout
format console
level debug
}
reverse_proxy /api/* {
to srv+http://backend-staging.service.fsn1.consul
}
reverse_proxy {
to srv+http://frontend-staging.service.fsn1.consul
}
}
3. The problem I’m having:
A couple of problems:
When I open the admin on 127.0.0.1:2019 I am getting a 404.
When I use curl to access the server I am getting a SSL error. With both the Host header set or not set.
curl -v -H "Host: dev3.foo.com" https://127.0.0.1
* Expire in 0 ms for 6 (transfer 0x55e010cebfb0)
* Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x55e010cebfb0)
* Connected to 127.0.0.1 (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: none
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, internal error (592):
* error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
* Closing connection 0
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
in the log I see
2021/03/09 23:46:03.528 DEBUG http.stdlib http: TLS handshake error from 127.0.0.1:49064: no certificate available for '127.0.0.1'
In the full log (below) I am seeing continuous TLS handshake errors for quora.com a domain I don’t even own. I assume this is someone sending a requests with the host header set to quora.com but to that IP? I assume with 2) fixed this should be OK to ignore.
4. Error messages and/or full log output:
./caddy run -config Caddyfile
2021/03/09 23:19:13.282 INFO using provided configuration {"config_file": "Caddyfile", "config_adapter": ""}
2021/03/09 23:19:13.285 INFO admin admin endpoint started {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["127.0.0.1:2019", "localhost:2019", "[::1]:2019"]}
2021/03/09 23:19:13.285 INFO http server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2021/03/09 23:19:13.285 INFO http enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"}
2021/03/09 23:19:13.285 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc00039d2d0"}
2021/03/09 23:19:13.286 DEBUG http starting server loop {"address": "[::]:443", "http3": false, "tls": true}
2021/03/09 23:19:13.286 DEBUG http starting server loop {"address": "[::]:80", "http3": false, "tls": false}
2021/03/09 23:19:13.286 INFO http enabling automatic TLS certificate management {"domains": ["dev3.foo.com"]}
2021/03/09 23:19:13.287 DEBUG tls loading managed certificate {"domain": "dev3.foo.com", "expiration": "2021/06/07 22:04:30.000", "issuer_key": "acme-v02.api.letsencrypt.org-directory", "storage": "FileStorage:/root/.local/share/caddy"}
2021/03/09 23:19:13.287 INFO tls cleaned up storage units
2021/03/09 23:19:13.301 INFO autosaved config {"file": "/root/.config/caddy/autosave.json"}
2021/03/09 23:19:13.301 INFO serving initial configuration
2021/03/09 23:19:14.682 DEBUG http.stdlib http: TLS handshake error from 37.129.73.186:52876: no certificate available for 'quora.com'
2021/03/09 23:19:18.183 DEBUG http.stdlib http: TLS handshake error from 2.147.183.203:60811: no certificate available for 'quora.com'
2021/03/09 23:19:24.101 DEBUG http.stdlib http: TLS handshake error from 37.129.73.186:52878: no certificate available for 'quora.com'
2021/03/09 23:19:33.543 DEBUG http.stdlib http: TLS handshake error from 37.129.73.186:52880: no certificate available for 'quora.com'
...
5. What I already tried:
I search the forum. This sounded similar - but I have a domain specified.
Plus I see the information about the cert in the log.
This really heavily implies the Host header wasn’t set. That’s pretty weird considering the very obvious -H "Host: dev3.foo.com" in your curl command.
Try using --resolve instead of -H and see if curl sends SNI properly:
Alright, so 2) was just a matter of Caddy rejecting the connection early because there was no SNI, a problem that shouldn’t pop up in production / when DNS is configured.
Getting requests for quora.com is pretty weird still, but not really in your power to do anything about (unless you know who the heck is sending those requests).
404s for the admin interface is also strange. Have you tried localhost:2019?
Odd. I tested in the browser first. Then went to curl to make it more reproducible. But fair enough. Maybe a glitch. And I learned something new with curl
…but why is the admin giving me a 404?
And is there a way to prevent adding the /api to the request to upstream?
Do you mean, stop the client from requesting the /api path?
I don’t think there’s anything Caddy would be doing to explicitly add it, it should be passing the path through exactly as presented by the client.
This is very strange indeed, especially given the log output: 2021/03/09 23:19:13.285 INFO admin admin endpoint started {"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["127.0.0.1:2019", "localhost:2019", "[::1]:2019"]}
Just to double confirm, you definitely don’t have Caddy containerized in any way?
(i.e. empty/catch-all matcher) should reverse proxy all requests (regardless of whether they start with /api) and should not modify the URI in any way when proxying them upstream (so the URI the client requests should be the exact URI the upstream receives).
A matcher, on its own, never modifies a request. It’s only ever a conditional.
I’m not sure what the problem with your original post’s config would be:
To my understanding, with this configuration, a request to (for example):
dev3.foo.com/api/bar
Should result in Caddy sending a request to the upstream with the URI /api/bar (i.e. unmodified).
Since the matcher for the backend handler requires the path /api/*, by definition, the only requests being sent to this upstream should always be prefixed with /api/.
Can you give me any specific examples of requests that aren’t being handled correctly with this setup?
That’s exactly what I was expecting. It’s just not what I am seeing at the moment.
I am wondering if there is easy way to intercept the traffic. Maybe with tcpdump?
This request isn’t being sent to the backend, it’s being sent to the frontend.
A request to /api does not match the path matcher /uri/* (pay close attention to that last slash before the wildcard).
If you requested /api/, that should get a backend response.
If you wanted to get a backend response for the literal URI /api, you’ll need to change your config a bit. You could set the backend path matcher to /api*, but then you’d filter in requests for /apifoo etc, which might not be a practical problem but most likely isn’t correct.
Instead, a common config pattern for handling this is: