caddy: Reverse proxy is not working with Mercure module
I have a Caddy binary w/ mercure module. And I have a Caddy on the system for anything else from a PPA. (w/o any modules, just factory default Caddy)
If I try to connect to the server w/ javascript, it will return w/ http 200 and close the connection because http header error instead of keep the connection as an event-stream. However the http request headers are OK.
Error message in browser:
EventSource's response has a MIME type ("text/plain") that is not "text/event-stream". Aborting the connection.
1.) Not working w/ Caddy
Mercure settings w/ Caddyfile
I started a caddy binary w/ a pre-built mercure module. $ ./caddy run -config Caddyfile
{
admin 0.0.0.0:2020
http_port 8080
}
mercure.test:8080
log {
output file access.log
}
route {
encode zstd gzip
mercure {
transport_url {$MERCURE_TRANSPORT_URL:bolt://mercure.db}
publisher_jwt xxxxxxxx
subscriber_jwt xxxxxxx
cors_origins http://test.local https://test.local http://localhost http://127.0.0.1
publish_origins *
subscriptions
}
respond /healthz 200
respond "Not Found" 404
}
The website’s (Symfony project) Caddy config
test.local {
root * /var/www/test/public
encode gzip zstd
file_server
php_fastcgi unix//run/php/php8.0-fpm.sock
# fig 1 --> IT DOES NOT WORK
reverse_proxy /.well-known/mercure {
to mercure.test:8080
}
# fig 2 --> IT DOES NOT WORK
reverse_proxy /.well-known/mercure mercure.test:8080
# fig 3 --> IT DOES NOT WORK
handle_path /.well-known/mercure {
rewrite * /.well-known/mercure
reverse_proxy mercure.test:8080
}
# fig x --> I tried w/ a lot of way what I forgot later...
log {
output file /var/log/caddy/test.access.log {
roll_size 3MiB
roll_keep 5
roll_keep_for 48h
}
format console
}
}
The js code it does not matter because w/ nginx it is working properly. But, for the connection I use EventSource:
Js code
const eventSource = new EventSource('https://test.local/.well-known/mercure', {
withCredentials: true
});
Caddy log
2022/01/07 09:52:16.128 INFO http.log.access handled request {"request": {"remote_addr": "127.0.0.1:37472", "proto": "HTTP/1.1", "method": "GET", "host": "test.local", "uri": "/.well-known/mercure?topic=xxxxx", "headers": {"User-Agent": ["Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0"], "Referer": ["https://test.local/admin"], "X-Forwarded-For": ["127.0.0.1"], "Cookie": ["mercureAuthorization=xxxxx; XDEBUG_SESSION=PHPSTORM; i_like_gitea=db38ff893f25a3a2; PHPSESSID=envdj5o0rrs8cu04fu8aqffq5f"], "Sec-Fetch-Site": ["same-origin"], "Te": ["trailers"], "X-Forwarded-Proto": ["https"], "Accept-Encoding": ["gzip, deflate, br"], "Accept": ["text/event-stream"], "Accept-Language": ["en-US,en;q=0.5"], "Cache-Control": ["no-cache"], "Pragma": ["no-cache"], "Sec-Fetch-Dest": ["empty"], "Sec-Fetch-Mode": ["cors"]}}, "common_log": "127.0.0.1 - - [07/Jan/2022:10:52:16 +0100] \"GET /.well-known/mercure?topic=xxxxx HTTP/1.1\" 0 0", "user_id": "", "duration": 0.000002843, "size": 0, "status": 0, "resp_headers": {"Server": ["Caddy"]}}
2.) Working solution w/ nginx
Nginx config in a virtual server
location /.well-known/mercure {
proxy_pass http://mercure.test:8080;
}
Caddy log
2022/01/07 09:54:13.324 INFO http.handlers.mercure New subscriber {"subscriber": {"id": "urn:uuid:7278e1bd-8f0c-40ec-a25f-92ab1ea14b32", "last_event_id": "", "remote_addr": "127.0.0.1:37474", "topic_selectors": ["2db5d020-abbb-4638-a6c3-43276b3626fb"], "topics": ["2db5d020-abbb-4638-a6c3-43276b3626fb"]}}
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 31 (14 by maintainers)
For anyone, who want to use the Mercure protocol easily; If you can do this, then do not use apache or nginx and so on, use just Caddy.
If you cannot use Caddy only, then you do not worth to read further. 😞
1.) Install the newest version of GoLang if you do not have on your system.
2.) Install xcaddy and build a custom Caddy binary.
3.) Set up the service manually.
4.) Then, you can set up your domain in caddy include your mercure settings. Example setting
/etc/caddy/Caddyfile
/etc/caddy/conf.d/your-domain.caddy
The only disadvantage (it is so annoying) of this setup, there is no general solution to upgrade your Caddy w/ the system. For example w/ a package manager. A hook might can help you, with the xcaddy command, if you use Arch. On Debian - as I know - there are hooks too in
dpkg.Alright well at this point I think I’ll close this issue because if you’ve found a workaround and we’ve not heard complaints from other people since, I have to assume it’s not a problem in general.
Okay, interesting. So comparing the two log messages:
So looking at the request headers in each, these are the header differences:
"Connection": ["close"]"X-Forwarded-Proto": ["https"],"X-Forwarded-For": ["127.0.0.1"],"Te": ["trailers"],I highly doubt the
X-Forwardedheaders are problematic here.Caddy explicitly removes the
Connectionheader when proxying because it’s a “hop-by-hop” header. I don’t think Caddy or the Go stdlib does anything with that header anyways.The
Tetrailers header is just an “announcement” that the client/proxy supports trailers, in case the upstream cares to use the feature. I don’t think mercure does in this case.So, I’m confused, basically. I think we’ll need help from @dunglas when he finds time, because I don’t know what to look for at this point.
If you refresh the browser or something, it would close the connection, right? We might see the access log written at that point.
Access logs only have INFO and ERROR, so lowering the level to DEBUG doesn’t do anything.
Like Matt wrote, you need to use the
debugglobal option, which sets the level to DEBUG for all runtime logs (not just access logs).FWIW Caddy does have specific handling for
text/event-streamto turn off the flush interval:https://github.com/caddyserver/caddy/blob/4b9849c7922c3a0a7b1bd487f5d890fcff32aaba/modules/caddyhttp/reverseproxy/streaming.go#L110
Can you replicate this with the
debugglobal option turned on, for both Caddy instances? It would be helpful to see thereverse_proxymodule’s logs for this.Also to narrow it down, to make sure it’s not a more recent regression, could you also try with Caddy v2.4.0? We made some changes since that version which may or may not be related.