Hi -- I'm trying to proxy a Server Sent Event using traefik 3. The device I'm trying to proxy to is an SLZ06p7 SLZB-06p7 Zigbee Ethernet PoE USB LAN WIFI Adapter.
I've contacted the manufacturer of the device. Typically the web interface to the device is on port 80. They said SSE uses port 81 and their instructions were simply to open port 81 - no other details.
I'm under the understanding SSE is sent using a layer 7 (http) proxy rather than a layer 4 (tcp) proxy. Additionally from my understanding SSE's establish a communication stream from server to client. I've seen people referring to the headers such as:
header("X-Accel-Buffering: no");
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
I've also seen these nginx proxy parameters mentioned:
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
Supposedly there can't be any buffering of the stream, no caching and the mime type is text/even-stream.
Soooo -- that's just all background information. Just "theoretical" knowledge which may or may not have any relevance to this particular implementation. How would I actually go about setting this up? I really don't know how to configure Traefik for SSE? I can set request and response headers however do I need to set response headers?
I know it's asking a lot but I've just never dealt with SSE events before and the resources I'm using are pretty limited and unfortunately the manufacture of device (via their support forums), isn't being very helpful. I'd be greatful if someone could give me a heads up.
AFAIK will SSE simply work over http(s). If the application requires a dedicated port, then publish a Docker port, create an additional entrypoint and router with service and it should work.
In terms of the sans names, they are all listed on the SSL certificate. I don't think that is the problem.
When contacting the developer for the SLZ06p7 device, the forum moderator said if you go directly to the device IP:81 you should see the SSEs. Which in this case he was correct. Only strange part is this SSE broadcast works only in Chrome but not FF. That's another issue for another day.
so in my case within Chrome, if I visit: http://SLZB-06P7-host.domain.com:81
I will see the following:
However if I try to visit the same port 81 site through the reverse proxy: https://zc-host.domain.com:81 which should in theory proxy to http://SLZB-06P7-host.domain.com:81 I get a Internal Server Error
Examining the logs, I get the following:
{"level":"debug","time":"2025-01-01T13:51:53-06:00","caller":"github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/wrr/wrr.go:196","message":"Service selected by WRR: 2fa3f05fb18cabcc"}
{"level":"debug","error":"net/http: HTTP/1.x transport connection broken: unexpected EOF","time":"2025-01-01T13:51:53-06:00","caller":"github.com/traefik/traefik/v3/pkg/proxy/httputil/proxy.go:113","message":"500 Internal Server Error"}
So I'm kind of stuck. I've asked the developer of the project to send my any configuration for any reverse proxy that's been tested against for the SSEs, and I haven't heard back.
Now if I actually try to visit the application (https://zc-host.domain.com) I'm still getting the warning about the SSE, but if you in the debug window it's complaining about blocked:mixed-content
So the application is a requesting a http connection to SSE rather than an https connection which the reverse proxy is actually setup to serve?? So I'm guessing the error to this is because the original connection to the application was through an encrypted TLS connection but the SSE is trying to use http.
Like no-referrer-when-downgrade, strict-origin-when-cross-origin is secure: no referrer (Referer header and document.referrer) is present when the request is made from an HTTPS origin (secure) to an HTTP one (insecure). This way, if your website uses HTTPS (if not, make it a priority), your website's URLs won't leak in non-HTTPS requests—because anyone on the network can see these, so this would expose your users to man-in-the-middle-attacks.
Within the same origin, the Referer header value is the full URL.
It seems the app developer explicitly hard-coded "http" and port 81 into the source code. When you request the regular page via https, then the browser will not allow you to include content via http.
Tell the app developer that their app is and they should use the same scheme (http or https) for SSE that is used for the main page.
My example SSE app uses regular http and SSE on the same port, that would make it even easier. And it works fine on Firefox.
Can I ask a question? To be fair their app main page only supports http. It doesn't support https. Is it possible from the apps point of view to know if https was used from reverse proxy? Is scheme information passed? Is it easier to use SSE on a different or same port as the main app?
**Update
Talked to developer and he rolled the app and SSE to the same port. He stated he originally had them on the same port, but do to problem with the device app becoming "frozen" over http or significantly slowed, he split the two to different ports. Anyway I flashed the latest fw with the two combined back on the same port and am testing things as it usually takes about 2-3 days for the issue to manifest per prior testing.
Yes, the app should be able to check the protocol.
If the app is server-side-rendered, it can check if a X-Forwarded-Proto header is set to http or https, and should be able to set the protocol accordingly for the SSE link.
If the app is mostly JS on the client side, it can check for the currently used scheme of the URL and adapt the link accordingly.
Coming from the nginx world, it's a little bit of an enigma how traefik forwards headers. I believe the app is server-side-rendered. Traefik I take it passes an X-Forwarded-Proto? I'm aware this is a very common header as I've seen it in various nginx configs many times -- just not quite as versed in the traefik ways of doing things.