ostcar
(Oskar Hahn)
February 6, 2021, 11:17am
1
1. Caddy version (caddy version
):
Docker: caddy:2.3.0-alpine
2. How I run Caddy:
I run Caddy in a docker container.
a. System environment:
Docker
c. Service/unit/compose file:
caddy:
image: caddy:2.3.0-alpine
volumes:
- ../caddy/Caddyfile.dev:/etc/caddy/Caddyfile
depends_on:
- client
- server
- autoupdate
ports:
- "8000:8000"
d. My complete Caddyfile or JSON config:
{
# Enable debug output
debug
}
localhost:8000
reverse_proxy /system/* autoupdate:8002 {
flush_interval -1
}
@server {
path /apps/*
path /rest/*
path /server-version.txt
path /media/*
}
reverse_proxy @server server:8000
reverse_proxy client:4200
3. The problem I’m having:
The reverse_proxy autoupdate
can only handle http2 traffic. Therefore I want to add a request_matcher that checks, that the incoming request uses http2. If http1 or http1.1 is used, then I want to return an error message to the client.
The reason is, that the autoupdate-server uses long living http connections. If a browser would use http1.1, it would block the connection and the max-connections-limit by the browser would be reached very soon.
5. What I already tried:
I looked at this list of request matchers but could not find any that could fit
Hmm. I think you could match on the {http.request.proto}
placeholder, which should contain either HTTP/1.0
, HTTP/1.1
or HTTP/2
.
You can pair this with a CEL expression matcher, since there’s no matcher that can do this on its own:
@http2only expression {http.request.proto} == "HTTP/2"
Or maybe, for example:
@http1 expression {http.request.proto}.startsWith("HTTP/1")
1 Like
ostcar
(Oskar Hahn)
February 6, 2021, 6:15pm
3
Thank you. That was the correct tip.
I use the following config:
@autoupdate {
path /system/*
expression {http.request.proto}.startsWith("HTTP/2")
}
reverse_proxy @autoupdate autoupdate:8002 {
flush_interval -1
}
@autoupdate_http1 {
path /system/*
expression {http.request.proto}.startsWith("HTTP/1")
}
respond @autoupdate_http1 "HTTP1 not supported" 400 {
close
}
This is the result:
curl -k --http1.1 https://localhost:8000/system/health
HTTP1 not supported`
curl -k --http2 https://localhost:8000/system/health
{"healthy": true}
The full value of http.request.proto
seems to be HTTP/2.0
I also tried:
@autoupdate {
path /system/*
expression {http.request.proto} == "HTTP/2.0"
}
reverse_proxy @autoupdate autoupdate:8002 {
flush_interval -1
}
But this does not work. Caddy fails to start and logs:
caddy_1 | run: loading initial config: loading new config: loading http app module: provision http: server srv0: setting up route handlers: route 0: loading handler modules: position 0: loading module 'subroute': provision http.handlers.subroute: setting up subroutes: route 1: loading matcher modules: module name 'expression': provision http.matchers.expression: compiling CEL program: ERROR: <input>:1:52: undeclared reference to 'HTTP' (in container '')
caddy_1 | | caddyPlaceholder(request, "http.request.proto") == HTTP/2.0
caddy_1 | | ...................................................^
Do you know what is wrong? I think to match the hole string instead of using .startsWith(…) would be nicer.
Ah, it’s because Caddy is removing the "
characters because it uses them as a token delimiter. If you instead wrap the whole thing with ` (backticks), the other token delimiter in Caddy, then it should work:
expression `{http.request.proto} == "HTTP/2.0"`
The CEL compiler was thinking HTTP
is a variable name and that you’re trying to divide it by two
1 Like
system
(system)
Closed
March 8, 2021, 11:18am
6
This topic was automatically closed after 30 days. New replies are no longer allowed.