javascript/Vue.js app behind Traefik v2.0

Hi,

I have a problem with a dashboard app which is supposed to run behind Traefik with the PathPrefix /dashboard.

services:
  traefik2:
    image: traefik:v2.0
    container_name: traefik
    labels:
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.docker.network=mynetwork"
    ports:
      - "80:80"     # The HTTP port
      - "443:443"   # The HTTPS port
      - "8080:8080" # The Web UI (enabled by --api)
    restart: unless-stopped
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./traefikfreyja.toml:/etc/traefik/traefik.toml"
      - "./dynamic_conf.toml:/etc/traefik/dynamic_conf.toml"
      - "./acme.json:/etc/traefik/acme/acme.json"

  dashboard:
    image: myproject/dashboard:latest
    container_name: dashboard
    ports:
      - "3000:3000" # To see that the container is running fine
    labels: 
      - "traefik.enable=true"
      - "traefik.docker.network=mynetwork"
      - "traefik.http.routers.dashboard.entrypoints=http"
      - "traefik.http.routers.dashboard.rule=PathPrefix(`/dashboard`)"
      - "traefik.http.middlewares.dashboard_prefix.stripprefix.prefixes=/dashboard"
      - "traefik.http.routers.dashboard.middlewares=dashboard_prefix"

It is a Vue.js app with base-prefix "/" and listens on port 3000.

It seems that the path javascript request path is not found, because it is lacking port.

Dashboard with Traefik, invalid request URL

Request URL: http://IP/_nuxt/dcee460c18ece3413659.js
Request Method: GET
Status Code: 404 Not Found
Remote Address: IP:80
Referrer Policy: no-referrer-when-downgrade
Content-Length: 19
Content-Type: text/plain; charset=utf-8
Date: Wed, 25 Sep 2019 12:58:56 GMT
X-Content-Type-Options: nosniff
Provisional headers are shown
Referer: http://IP/dashboard/replication
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36

Dashboard without Traefik, correct request URL

Request URL: http://IP:3000/_nuxt/dcee460c18ece3413659.js
Request Method: GET
Status Code: 200 OK (from memory cache)
Remote Address: IP:3000
Referrer Policy: no-referrer-when-downgrade
Accept-Ranges: bytes
Cache-Control: public, max-age=31536000
Connection: keep-alive
Content-Encoding: gzip
Content-Type: application/javascript; charset=UTF-8
Date: Wed, 25 Sep 2019 10:26:10 GMT
ETag: W/"923-16d635b9b78"
Last-Modified: Tue, 24 Sep 2019 13:00:11 GMT
Transfer-Encoding: chunked
Vary: Accept-Encoding
Provisional headers are shown
Referer: http://IP:3000/replication
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36

Any idea on how to solve this?

Hi ,@gauteoh

I think you missed the part where you define the port in the labels of your app container.

- "traefik.http.services.myservice.loadbalancer.server.port=3000"

https://docs.traefik.io/v2.0/routing/providers/docker/#services

And it's not nessecary to expose the port on your docker as traefik will reach it with the network you define.

1 Like

It seems that traefik automatically detects the port based on the EXPOSE settings in the docker image. I have set EXPOSE 3000 in my dockerfile and it automatically creates a service and routes it correctly to the internal ip on port 3000.

I also tried what you proposed, but the request URL is still invalid.

Could you please share your toml files without the sensitives informations ?

Also, I think there is an error in this part :

      - "traefik.http.routers.dashboard.rule=PathPrefix(`/dashboard`)"
      - "traefik.http.middlewares.dashboard_prefix.stripprefix.prefixes=/dashboard"

You don't have to strip the prefix /dashboard, as all your request to http://domain.com/dashboard will be routed to http://container_ip/

Maybe try something like this :

 dashboard:
    image: myproject/dashboard:latest
    container_name: dashboard
    ports:
      - "3000:3000" # To see that the container is running fine
    labels: 
      - "traefik.enable=true"
      - "traefik.docker.network=mynetwork"
      - "traefik.http.routers.dashboard.entrypoints=http"
      - "traefik.http.routers.dashboard.rule=PathPrefix(`/dashboard`)"

      - "traefik.http.services.dashboard.loadbalancer.server.port=3000"

You don't have to strip the prefix /dashboard, as all your request to http://domain.com/dashboard will be routed to http://container_ip/

Cool, I was not aware of that! Thought the path also was sent to the container. I want the dashboard to be available on http://domain.com/dashboard and not on root.

This is my traefik.toml file.

[log]
  level = "DEBUG"


# Entrypoints to be used by frontends that do not specify any entrypoint.
# Each frontend can specify its own entrypoints.
#defaultEntryPoints = ["http", "https"]

[entryPoints]
  [entryPoints.http]
    address = ":80"
    [entryPoints.http.forwardedHeaders]
      insecure = true
  [entryPoints.https]
    address = ":443"

[api]
  insecure = true

# Enable Docker configuration backend
[providers]
  [providers.file]
    directory = "/etc/traefik"
    filename = "dynamic_conf.toml"
    watch = true
    debugLogGeneratedTemplate = true
  [providers.docker]
    endpoint = "unix:///var/run/docker.sock"
    watch = true
    exposedByDefault = false

The dynamic_conf.toml is empty

hi, were you able to make the vue dashboard work behind traefik?

Hi, yes we were able to. We specified another base in nuxt.config.js:

  router: {
    base: '/dashboard'
  },

Hi, can you please share your working docker-compose for the dashboard.

Thanks this helped me figuring out how to serve dev server while behind traefik.
One think though. the following label settings where transparent:

labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frontend.rule=Host(`frontend.service.localhost`)"
      - "traefik.docker.network=traefik"

I had to add the rule with loadbalancer service and also create a vue.config.js file (at the same level as the package.json file) with the following content:

module.exports = {
    devServer: {
        public: 'frontend.service.localhost',
        port: 80,
        compress: true,
    }
}

Maybe there is way to do it without the vue.config.js file. if so that would be great, since I don't won't to have that suff configured in the app