1

I have the barebones example SvelteKit app & a Traefik reverse proxy both running inside Docker containers.

When accessing the SK app directly (i.e. without going through Traefik first), the page content loads just fine:

"Welcome to SvelteKit" example page

However, when accessing it via Traefik, at the /sv-test path (as I intend to do under normal circumstances), the basic HTML scaffolding loads the same, but the actual text content is a generic 404 Not Found message:

"404 Not Found" with same formatting as the typical SvelteKit example page

The issue with loading the page content appears to have to do with the expected MIME type being incorrect for some reason, as the browser console showed these messages:

Loading module from “*http://192.168.1.149/node_modules/.pnpm/@sveltejs+kit@2.21.5_@sveltejs+vite-plugin-svelte@5.1.0_svelte@5.34.7_vite@6.3.5__svelte@5.34.7_vite@6.3.5/node_modules/@sveltejs/kit/src/runtime/client/entry.js*” was blocked because of a disallowed MIME type (“text/plain”).

Loading module from “*http://192.168.1.149/@fs/srv/.svelte-kit/generated/client/app.js*” was blocked because of a disallowed MIME type (“text/plain”).

...

Uncaught (in promise) TypeError: error loading dynamically imported module: http://192.168.1.149/node_modules/.pnpm/@sveltejs+kit@2.21.5_@sveltejs+vite-plugin-svelte@5.1.0_svelte@5.34.7_vite@6.3.5__svelte@5.34.7_vite@6.3.5/node_modules/@sveltejs/kit/src/runtime/client/entry.js

But why would the issue only arise when accessing the page via Traefik?


Here's my current Docker Compose & Traefik configuration:

compose.yaml:

services:
  traefik:
    container_name: traefik
    image: traefik:latest
    restart: unless-stopped
    security_opt: [ no-new-privileges=true ]
    networks: [ frontend ]
    ports:
      - 80:80
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yaml:/traefik.yaml:ro

...

sv-test: container_name: sv-test build: { target: sv-test } restart: unless-stopped security_opt: [ no-new-privileges=true ] networks: [ frontend ] ports: [ 5173:5173 ] labels: - traefik.enable=true - traefik.http.routers.sv-test.rule=Path(/sv-test) #- traefik.http.services.sv-test.loadbalancer.server.port=5173

networks: frontend: name: frontend #enable_ipv4: false enable_ipv6: true ipam: { config: [ { subnet: 2001:db8:2::/64 } ] }

traefik.yaml:

api:
  dashboard: true
  insecure: true
  debug: false
entryPoints:
  web:
    address: :80
    asDefault: true
  # websecure:
  #   address: :443
providers:
  docker:
    endpoint: unix:///var/run/docker.sock
    exposedByDefault: false
    network: frontend
G.S.
  • 31

1 Answers1

1

After looking more closely at the console output in my question, I realized that the HTTP requests for server resources were assuming that the site's base path was "/" rather than "/sv-test/", so the resource URIs were constructed incorrectly, e.g. as "http://192.168.1.149/favicon.ico" instead of "http://192.168.1.149/sv-test/favicon.ico". This didn't arise when accessing the site directly at the exposed Vite port 5173, without routing through Traefik first, because in that case the presumption that the host component of the URL was the site's root was actually correct, so the subsequent requests would have actually found the intended resources.

At first glance, it seems like the easy fix would be to account for this within SvelteKit's configuration by adding a config.kit.paths.base property & setting it to "/sv-test", but there are a couple of issues with this approach. First, that property appends the base to the host even if the site is accessed from a separate URL, such as directly with the Vite port 5173 specified. More importantly, however, SvelteKit appears not to even work consistently with this property when run in development mode, as detailed in this answer to a related SO issue. Since I'm only operating with dev mode for the time being, and the eventual production environment would be entirely different anyway, I've chosen to forego this option for now.

So my workaround for now is either to ignore the Traefik reverse proxy entirely when it comes to that service:

compose.yaml:

# ...
services:
  # ...
  sv-test:
    # ...
    ports: [ 5173:5173 ]
    # No "labels" set anymore

or to set the Traefik router to match by entrypoint rather than by path:

compose.yaml:

# ...
services:
  traefik:
    # ...
    ports:
      - 80:80
      - 5173:5173
      - 8080:8080
  # ...
  sv-test:
    # ...
    labels:
      - traefik.enable=true
      - traefik.http.routers.sv-test.entrypoints=sv-test
      - traefik.http.routers.sv-test.rule=PathPrefix(`/`)

traefik.yaml:

# ...
entryPoints:
  # ...
  sv-test:
    address: :5173
G.S.
  • 31