traefik icon indicating copy to clipboard operation
traefik copied to clipboard

The tightening of url verification in 3.4 led to the fact that modules cannot be connected to nuxt

Open sliva-name opened this issue 3 weeks ago • 6 comments

Welcome!

  • [x] Yes, I've searched similar issues on GitHub and didn't find any.
  • [x] Yes, I've searched similar issues on the Traefik community forum and didn't find any.

What did you do?

Everything worked for me on version 3.0, but at some point I updated Docker, as a result of which traefik stopped running. After digging around, I found out that the problem was the incompatibility of the Docker API and Traefik versions. I updated Traefik to version 3.6 and it started, but the hmr modules in nuxt cannot connect, there are errors in the console. There was no such thing in 3.0. I started to look further and found that the rules for urls were tightened in version 3.4, apparently Traefik replaces or truncates the url and modules cannot connect, errors fall into the console.

What did you see instead?

If more detailed information is needed, I can reproduce the errors from the console, so far I have solved it by running nuxt on a separate port in docker instead of using traefik.

Image

What version of Traefik are you using?

3.6.4

What is your environment & configuration?

version: '3.8'

services:
  traefik:
    image: traefik:v3.6
    container_name: traefik
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
    ports:
      - "8080:80"
      - "8443:443"
      - "8081:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - app-network
    restart: unless-stopped

  backend:
    build:
      context: ../backend
      dockerfile: Dockerfile
      args:
        - USER_ID=${USER_ID:-1000}
        - GROUP_ID=${GROUP_ID:-1000}
    container_name: backend
    user: "${USER_ID:-1000}:${GROUP_ID:-1000}"
    working_dir: /var/www/html
    volumes:
      - ../backend:/var/www/html
    networks:
      - app-network
    environment:
      - APP_URL=http://api.localhost:8080
      - DB_CONNECTION=pgsql
      - DB_HOST=db
      - DB_PORT=5432
      - DB_DATABASE=${DB_DATABASE:-laravel}
      - DB_USERNAME=${DB_USERNAME:-laravel}
      - DB_PASSWORD=${DB_PASSWORD:-secret}
      - REDIS_HOST=redis
      - SCOUT_DRIVER=meilisearch
      - SCOUT_QUEUE=true
      - MEILISEARCH_HOST=http://meilisearch:7700
      - MEILISEARCH_KEY=${MEILISEARCH_KEY:-masterKey}
      - USER_ID=${USER_ID:-1000}
      - GROUP_ID=${GROUP_ID:-1000}
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.backend.rule=Host(`api.localhost`)"
      - "traefik.http.routers.backend.entrypoints=web"
      - "traefik.http.services.backend.loadbalancer.server.port=8000"
    depends_on:
      - db
      - redis
      - meilisearch
    restart: unless-stopped

  queue:
    build:
      context: ../backend
      dockerfile: Dockerfile
      args:
        - USER_ID=${USER_ID:-1000}
        - GROUP_ID=${GROUP_ID:-1000}
    container_name: queue
    user: "${USER_ID:-1000}:${GROUP_ID:-1000}"
    working_dir: /var/www/html
    volumes:
      - ../backend:/var/www/html
    networks:
      - app-network
    environment:
      - APP_URL=http://api.localhost:8080
      - DB_CONNECTION=pgsql
      - DB_HOST=db
      - DB_PORT=5432
      - DB_DATABASE=${DB_DATABASE:-laravel}
      - DB_USERNAME=${DB_USERNAME:-laravel}
      - DB_PASSWORD=${DB_PASSWORD:-secret}
      - REDIS_HOST=redis
      - SCOUT_DRIVER=meilisearch
      - SCOUT_QUEUE=true
      - MEILISEARCH_HOST=http://meilisearch:7700
      - MEILISEARCH_KEY=${MEILISEARCH_KEY:-masterKey}
      - USER_ID=${USER_ID:-1000}
      - GROUP_ID=${GROUP_ID:-1000}
    command: php artisan horizon
    depends_on:
      - backend
      - redis
    restart: unless-stopped

  frontend:
    build:
      context: ../frontend
      dockerfile: Dockerfile
      args:
        - USER_ID=${USER_ID:-1000}
        - GROUP_ID=${GROUP_ID:-1000}
    container_name: frontend
    user: "${USER_ID:-1000}:${GROUP_ID:-1000}"
    working_dir: /app
    volumes:
      - ../frontend:/app
    ports:
      - "3000:3000"
    networks:
      - app-network
    environment:
      - USER_ID=${USER_ID:-1000}
      - GROUP_ID=${GROUP_ID:-1000}
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frontend.rule=Host(`localhost`)"
      - "traefik.http.routers.frontend.entrypoints=web"
      - "traefik.http.services.frontend.loadbalancer.server.port=3000"
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    container_name: db
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
      POSTGRES_DB: ${DB_DATABASE:-laravel}
      POSTGRES_USER: ${DB_USERNAME:-laravel}
      PGDATA: /var/lib/postgresql/data/pgdata
    volumes:
      - db-data:/var/lib/postgresql/data
    networks:
      - app-network
    ports:
      - "5432:5432"
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-laravel}"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: redis
    networks:
      - app-network
    ports:
      - "6379:6379"
    restart: unless-stopped

  meilisearch:
    image: getmeili/meilisearch:v1.10
    container_name: meilisearch
    ports:
      - "7700:7700"
    environment:
      - MEILI_MASTER_KEY=${MEILISEARCH_KEY:-masterKey}
      - MEILI_NO_ANALYTICS=true
    volumes:
      - meili-data:/meili_data
    networks:
      - app-network
    restart: unless-stopped
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.meilisearch.rule=Host(`search.localhost`)"
      - "traefik.http.routers.meilisearch.entrypoints=web"
      - "traefik.http.services.meilisearch.loadbalancer.server.port=7700"

networks:
  app-network:
    driver: bridge

volumes:
  db-data:
  meili-data:

Add more configuration information here.

If applicable, please paste the log output in DEBUG level

No response

sliva-name avatar Dec 07 '25 14:12 sliva-name

Update: Root cause identified — PR #12360 breaks URL encoding compliance

The issue is specifically caused by the change in PR #12360 where Traefik now rejects ALL URLs containing %2F (encoded forward slash) in paths.

For Nuxt.js applications, this breaks:

  • Dynamic routes with encoded parameters
  • Module loading paths
  • Any API proxy where / needs to be passed as a parameter

Example broken Nuxt scenario: Nuxt dynamic route: /api/[module]/[action] Becomes: /api/module%2Faction (when module contains '/') Result in 3.6.4: 400 Bad Request

sliva-name avatar Dec 07 '25 20:12 sliva-name

@dtomcej @ldez

Это изменение нарушает работу Nuxt.js приложений (и многих других).

Как автор проблемы №12383, я могу подтвердить, что это делает Traefik 3.6.4+ ** несовместимым ** со стандартом Nuxt.js шаблоны маршрутизации, в которых закодированные косые черты являются вполне допустимыми.

** Проблема:** Nuxt (и многие современные фреймворки) используют закодированные символы в путях для динамической маршрутизации. Полное отклонение %2F аналогично отклонению %20 (пробелы) — это нарушает веб-стандарты.

Запрос: Либо:

  1. Полностью отмените это изменение
  2. Добавьте параметр конфигурации, чтобы отключить его
  3. Сделайте так, чтобы оно применялось только к началу путей (а не к середине/концу)

Прямо сейчас всем разработчикам Nuxt, использующим Traefik, запрещено обновляться после версии 3.6.2.

sliva-name avatar Dec 07 '25 20:12 sliva-name

Еще одно подтверждение

Image

sliva-name avatar Dec 07 '25 20:12 sliva-name

Hello @sliva-name,

Thank you for reporting this issue, and we apologise for the inconvenience.

Does my comment on #12360 answer this issue?

rtribotte avatar Dec 08 '25 10:12 rtribotte

Yes, now I understand the reason, but it still breaks my work, what should I do?

sliva-name avatar Dec 08 '25 11:12 sliva-name

@sliva-name By looking at the last screenshot you have shared, the problem lies with encoded slashes (%2F), since they are rejected by default now.

You can allow them on you entryPoints with: --entryPoints.web.http.encodedCharacters.allowEncodedSlash=true and --entryPoints.websecure.http.encodedCharacters.allowEncodedSlash=true

rtribotte avatar Dec 08 '25 13:12 rtribotte

Hey there,

It looks like the question is answered. I close the issue accordingly.

Please feel free to leave a comment if you disagree; we'll reopen if necessary.

nmengin avatar Dec 11 '25 13:12 nmengin