[GH-ISSUE #1169] [Bug]: gcode viewer broken behind reverse proxy: trailing-slash 404 + restrictive CSP #845

Closed
opened 2026-05-06 12:33:22 +02:00 by BreizhHardware · 1 comment

Originally created by @penmoid on GitHub (Apr 29, 2026).
Original GitHub issue: https://github.com/maziggy/bambuddy/issues/1169

Originally assigned to: @maziggy on GitHub.

Component

Bambuddy

Bug Description

Three issues block the gcode viewer (and the broader Bambuddy UI) when running Bambuddy behind a TLS-terminating reverse proxy. All are server-side / packaging defaults — not configuration the operator can fix without rewriting headers in front of Bambuddy.

1. /gcode-viewer/ (trailing slash) returns 404

The frontend renders the gcode-viewer iframe with src=\"/gcode-viewer/?archive=...&plate=...\" (trailing slash), but the FastAPI backend only registers the route without a trailing slash:

GET /gcode-viewer       → 200  (serves SPA index.html)
GET /gcode-viewer/      → 404  {\"detail\":\"Not Found\"}
GET /gcode-viewer/?archive=239&plate=2  → 404

Result: opening the gcode viewer from the printer detail page just shows "Not Found." Either the route should be registered with both forms, or FastAPI should be configured with redirect_slashes=True (it's True by default unless explicitly disabled).

2. Default CSP connect-src is missing https://fonts.gstatic.com

The shipped Content-Security-Policy header includes:

connect-src 'self' ws: wss:;
font-src ... https://fonts.gstatic.com;

But the service worker (sw.js) fetches Inter .woff2 files via fetch(), which is governed by connect-src rather than font-src. Result, repeated on every page load:

Connecting to 'https://fonts.gstatic.com/s/inter/v20/...woff2' violates the
following Content Security Policy directive: \"connect-src 'self' ws: wss:\"
…
Failed to decode downloaded font
OTS parsing error: invalid sfntVersion: 1008821359

Fix: add https://fonts.gstatic.com to connect-src (and confirm https://fonts.googleapis.com is there too — needed when the SW prefetches the CSS).

3. Default CSP child-src 'none' blocks the gcode viewer iframe

Even after fixing #1, the iframe still won't render:

Framing 'https://.../gcode-viewer/?archive=239&plate=2' violates the following
Content Security Policy directive: \"child-src 'none'\". The request has been
blocked. Note that 'frame-src' was not explicitly set, so 'child-src' is used
as a fallback.

Since the gcode viewer is served from the same origin, child-src 'self' (or frame-src 'self') is required for a feature shipped with the product to actually work.

Expected Behavior

Out of the box behind a reverse proxy:

  1. /gcode-viewer/ (with or without trailing slash) returns the SPA so the iframe loads.
  2. The CSP allows the resources Bambuddy itself loads — connect-src should include https://fonts.gstatic.com (and https://fonts.googleapis.com), and child-src/frame-src should allow 'self' so the gcode viewer iframe renders.

Steps to Reproduce

  1. Deploy ghcr.io/maziggy/bambuddy:daily behind a reverse proxy that terminates TLS (in my case Traefik on Kubernetes; same behavior reproduces on any TLS-terminating proxy).
  2. Open the web UI and add a printer. Watch the browser console — connect-src violations for fonts.gstatic.com log on every page load.
  3. Open a printer's history, pick a print, click "View G-code." Iframe shows "Not Found" (path 404) and console shows child-src 'none' violation.

Workarounds applied externally (Traefik middleware)

For anyone hitting this, the issue can be worked around without modifying the image:

  • Trailing slash: redirectRegex middleware that rewrites ^https?://([^/]+)/gcode-viewer/(\?.*)?$https://${1}/gcode-viewer${2}.
  • CSP: replace the response header with a policy that adds https://fonts.gstatic.com to connect-src and sets child-src 'self'; frame-src 'self';.
  • (Tangential) X-Forwarded-Proto: the WebSocket Origin check rejects https Origins when the upstream sees plain HTTP. Worth noting Bambuddy is sensitive to this — operators must inject X-Forwarded-Proto: https in front of Bambuddy or the live status WS won't connect. (See also #1096 for the spoolman variant.)

Bambuddy Version

ghcr.io/maziggy/bambuddy:daily@sha256:f68e024e88f00159c50e6a155c24d80652bcb63e0b7e82b36ca7f1fdfd386c73 (pulled 2026-04-29)

Printer Model

H2C / A1 Mini (not printer-specific — reproduces on the web UI itself)

Originally created by @penmoid on GitHub (Apr 29, 2026). Original GitHub issue: https://github.com/maziggy/bambuddy/issues/1169 Originally assigned to: @maziggy on GitHub. ### Component Bambuddy ### Bug Description Three issues block the gcode viewer (and the broader Bambuddy UI) when running Bambuddy behind a TLS-terminating reverse proxy. All are server-side / packaging defaults — not configuration the operator can fix without rewriting headers in front of Bambuddy. #### 1. `/gcode-viewer/` (trailing slash) returns 404 The frontend renders the gcode-viewer iframe with `src=\"/gcode-viewer/?archive=...&plate=...\"` (trailing slash), but the FastAPI backend only registers the route without a trailing slash: ``` GET /gcode-viewer → 200 (serves SPA index.html) GET /gcode-viewer/ → 404 {\"detail\":\"Not Found\"} GET /gcode-viewer/?archive=239&plate=2 → 404 ``` Result: opening the gcode viewer from the printer detail page just shows \"Not Found.\" Either the route should be registered with both forms, or FastAPI should be configured with `redirect_slashes=True` (it's True by default unless explicitly disabled). #### 2. Default CSP `connect-src` is missing `https://fonts.gstatic.com` The shipped `Content-Security-Policy` header includes: ``` connect-src 'self' ws: wss:; font-src ... https://fonts.gstatic.com; ``` But the service worker (`sw.js`) fetches Inter `.woff2` files via `fetch()`, which is governed by `connect-src` rather than `font-src`. Result, repeated on every page load: ``` Connecting to 'https://fonts.gstatic.com/s/inter/v20/...woff2' violates the following Content Security Policy directive: \"connect-src 'self' ws: wss:\" … Failed to decode downloaded font OTS parsing error: invalid sfntVersion: 1008821359 ``` Fix: add `https://fonts.gstatic.com` to `connect-src` (and confirm `https://fonts.googleapis.com` is there too — needed when the SW prefetches the CSS). #### 3. Default CSP `child-src 'none'` blocks the gcode viewer iframe Even after fixing #1, the iframe still won't render: ``` Framing 'https://.../gcode-viewer/?archive=239&plate=2' violates the following Content Security Policy directive: \"child-src 'none'\". The request has been blocked. Note that 'frame-src' was not explicitly set, so 'child-src' is used as a fallback. ``` Since the gcode viewer is served from the same origin, `child-src 'self'` (or `frame-src 'self'`) is required for a feature shipped with the product to actually work. ### Expected Behavior Out of the box behind a reverse proxy: 1. `/gcode-viewer/` (with or without trailing slash) returns the SPA so the iframe loads. 2. The CSP allows the resources Bambuddy itself loads — `connect-src` should include `https://fonts.gstatic.com` (and `https://fonts.googleapis.com`), and `child-src`/`frame-src` should allow `'self'` so the gcode viewer iframe renders. ### Steps to Reproduce 1. Deploy `ghcr.io/maziggy/bambuddy:daily` behind a reverse proxy that terminates TLS (in my case Traefik on Kubernetes; same behavior reproduces on any TLS-terminating proxy). 2. Open the web UI and add a printer. Watch the browser console — `connect-src` violations for `fonts.gstatic.com` log on every page load. 3. Open a printer's history, pick a print, click \"View G-code.\" Iframe shows \"Not Found\" (path 404) and console shows `child-src 'none'` violation. ### Workarounds applied externally (Traefik middleware) For anyone hitting this, the issue can be worked around without modifying the image: - **Trailing slash**: `redirectRegex` middleware that rewrites `^https?://([^/]+)/gcode-viewer/(\?.*)?$` → `https://${1}/gcode-viewer${2}`. - **CSP**: replace the response header with a policy that adds `https://fonts.gstatic.com` to `connect-src` and sets `child-src 'self'; frame-src 'self';`. - **(Tangential) X-Forwarded-Proto**: the WebSocket Origin check rejects `https` Origins when the upstream sees plain HTTP. Worth noting Bambuddy is sensitive to this — operators must inject `X-Forwarded-Proto: https` in front of Bambuddy or the live status WS won't connect. (See also #1096 for the spoolman variant.) ### Bambuddy Version `ghcr.io/maziggy/bambuddy:daily@sha256:f68e024e88f00159c50e6a155c24d80652bcb63e0b7e82b36ca7f1fdfd386c73` (pulled 2026-04-29) ### Printer Model H2C / A1 Mini (not printer-specific — reproduces on the web UI itself)
BreizhHardware 2026-05-06 12:33:22 +02:00
  • closed this issue
  • added the
    invalid
    label
Author
Owner

@penmoid commented on GitHub (Apr 29, 2026):

Closing — filed in error. Will re-open if/when intended.

<!-- gh-comment-id:4346950294 --> @penmoid commented on GitHub (Apr 29, 2026): Closing — filed in error. Will re-open if/when intended.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/bambuddy#845
No description provided.