Reverse proxy configuration

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.

1 Like