This was the smoking gun for me. Thanks for sharing.
In case someone is using Apache 2.4 (sudo apt info apache2
) as the reverse proxy:
Reverse proxy configuration Apache2 for Octoprint using a wildcard cert
Also can't edit the Wiki post, but if anyone is having issues with Traefik websockets:
It appears Octoprint isn't handling schema wss
provided by the X-Forwarded-Proto
header (which is being added by Traefik by default). This causes Octoprint to reject the Web Socket request with a 403, with Firefox considering this a NS_ERROR_WEBSOCKET_CONNECTION_REFUSED
error, aborting the web socket (which is slightly confusing, as it's obvious that a connection to Octoprint, through the reverse proxy, has been successfully made).
No specification disallows or allows for this schema, but wss
isn't exactly orthodox (so I wouldn't go as far as calling this a bug, on either side).
Ultimately the fix is something like this:
http:
middlewares:
https-redirect:
redirectScheme:
scheme: https
strip-camera-path:
stripPrefix:
prefixes:
- "/camera-1"
proto-headers:
headers:
customRequestHeaders:
X-Forwarded-Proto: "https"
routers:
octoprint:
rule: "Host(`octoprint.service.blah`)"
service: octoprint
middlewares:
- https-redirect
- proto-headers
octoprint-inline-camera:
rule: "Host(`octoprint.service.blah`) && Path(`/camera-1`)"
service: octoprint-camera
middlewares:
- https-redirect
- strip-camera-path
services:
octoprint:
loadBalancer:
servers:
- url: "http://127.0.0.1:8081"
octoprint-camera:
loadBalancer:
servers:
- url: "http://127.0.0.1:8080"
The important section is the proto-headers
middleware - used to override the wss
schema to https
.
http:
middlewares:
proto-headers:
headers:
customRequestHeaders:
X-Forwarded-Proto: "https"
...
routers:
octoprint:
middlewares:
- proto-headers
Basically, the /reverse_proxy_test/
test doesn't test web socket headers, so you'll silently have a really buggy UI when using Traefik with the default configuration.
I've followed the various advice here, with Traefik and Octoprint and NOTHING has worked. It's the only server/service on my network that I cannot figure out how to configure in Traefik. It should NOT be this hard.
I'm using the octoprint docker container with the mjpg-streamer, behind Traefik with the following config in my compose.yaml without any issues:
labels:
traefik.enable: true
traefik.http.routers.octoprint.entrypoints: web, websecure
traefik.http.routers.octoprint.rule: Host(`octoprint.saturn.hye.network`) && !Path(`/webcam`)
traefik.http.routers.octoprint.service: octoprint
traefik.http.routers.octoprint.tls: true
traefik.http.services.octoprint.loadbalancer.server.port: 5000
traefik.http.routers.octoprint_cam.entrypoints: web, websecure
traefik.http.routers.octoprint_cam.rule: Host(`octoprint.saturn.hye.network`) && Path(`/webcam`)
traefik.http.routers.octoprint_cam.service: octoprint_cam
traefik.http.routers.octoprint_cam.tls: true
traefik.http.routers.octoprint_cam.middlewares: stripprefix_cam
traefik.http.services.octoprint_cam.loadbalancer.server.port: 8080
traefik.http.middlewares.stripprefix_cam.stripprefix.prefixes: "/webcam"
It's important to set the stream URL of the Classic Webcam plugin to /webcam?action=stream
without the trailing slash after webcam.
I'm trying to switch my reverse proxy over from Nginx to Caddy (more specifically, caddy-docker-proxy). Nginx works properly, but when I try to proxy it with Caddy, it gives up with "socket connection failed." octoprint.log doesn't show any errors, but this error was logged by Caddy:
{"level":"error","ts":1729831392.5916576,"logger":"http.handlers.reverse_proxy","msg":"aborting with incomplete response","upstream":"am8.local:80","duration":0.015810937,"request":{"remote_ip":"192.168.1.1","remote_port":"50242","client_ip":"192.168.1.1","proto":"HTTP/2.0","method":"POST","host":"am8.alfter.us:1443","uri":"/sockjs/843/ctz1q3cw/xhr_streaming?t=1729831332571","headers":{"Accept-Language":["en-US,en;q=0.9"],"Accept-Encoding":["gzip, deflate, br, zstd"],"Dnt":["1"],"Sec-Ch-Ua":["\"Not?A_Brand\";v=\"99\", \"Chromium\";v=\"130\""],"Sec-Fetch-Dest":["empty"],"X-Forwarded-Proto":["https"],"Origin":["https://am8.alfter.us:1443"],"Priority":["u=1, i"],"Content-Length":["0"],"Sec-Fetch-Site":["same-origin"],"Accept":["*/*"],"Cookie":["REDACTED"],"Sec-Fetch-Mode":["cors"],"Sec-Ch-Ua-Platform":["\"Linux\""],"Sec-Ch-Ua-Mobile":["?0"],"X-Forwarded-For":["192.168.1.1"],"X-Forwarded-Host":["am8.alfter.us:1443"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"am8.alfter.us"}},"error":"reading: unexpected EOF"}
I'm using this docker-compose.yml to configure caddy-docker-proxy...since OctoPrint is actually running on a Raspberry Pi Compute Module 4 attached to the printer, I'm basically using a container that does nothing but configure the proxy:
services:
am8:
container_name: "am8"
image: "busybox:uclibc"
network_mode: none
command: [ "tail", "-f", "/dev/null" ]
labels:
caddy: am8.alfter.us
caddy.reverse_proxy: am8.local:80
I'm probably missing something in the Caddy config, but damned if I can figure it out.
Might be way off base here and I don't know anything about configuring Caddy but I would not expect you would point to port 80 if you did not have something additional in the route to port to 5000 which is what I would expect OctoPrint to be listening on.
Do you also have HAP installed on the compute module with OctoPrint? If not.. the OctoPrint install on your compute module should be listening on port 5000.
You can't connect to port 5000 in a standard OctoPi image, either connect to 80 or 443 which will forward to the port 5000 on the backend via haproxy running on the pi.
I figured it out before I saw the replies. I'd forgotten that the OctoPrint host (not OctoPi, but a custom image built on Alpine Linux) had Nginx reverse-proxying OctoPrint. Changing my caddy-docker-proxy config to go directly to OctoPrint (port 5000 instead of 80) cleared it right up.