MERN stack - api call from React not redirecting to back end with Traefik + docker

Hello,

I've created a project with React in the front end and Node+express in the back end. I dockerized my frontend and backend, and would like to add traefik so that when I do (in local for now):
localhost:3000/api/products (3000 is the port used in the frontend/client), it redirects to localhost:5000/api/products (5000 is the port used in the backend/server) and then sends back the response to my frontend.

Here is my docker-compose.yml file:

version: "3"
services:
    client:
        container_name: lgui-client
        build:
            context: ./client
            dockerfile: Dockerfile
        image: toscalivia83/lgui-client
        ports:
            - "3000:3000"
        volumes:
            - ./client/src/:/usr/src/app/src/
            - ./client:/usr/src/app
        labels:
            - "traefik.http.routers.rule=Host:localhost"
            - "traefik.http.routers.service=server"
            - "traefik.enable=true"
            - "traefik.port=8080"
        stdin_open: true
        tty: true
    reverse-proxy:
        image: traefik:v2.2
        command:
            - --entrypoints.web.address=:80
            - --providers.docker=true
            - --api.insecure
        ports:
            - "80:80"
            - "8080:8080"
        volumes:
            - /var/run/docker.sock:/var/run/docker.sock
    server:
        container_name: lgui-server
        build:
            context: ./server
            dockerfile: Dockerfile
        image: toscalivia83/lgui-server
        ports:
            - "5000:5000"
        volumes:
            - ./server/src/:/usr/src/app/src/
            - ./server:/usr/src/app
        stdin_open: true
        tty: true

and here is the traefik.toml file that I have created in the root of my project:

# http routing section
[http]
  [http.routers]
     # Define a connection between requests and services
     [http.routers.to-server]
      rule = "Host(`localhost`) && PathPrefix(`/api/`)"
      service = "lg-server"

  [http.services]
    # Define how to reach an existing service on our infrastructure
    [http.services.lg-server.loadBalancer]
      [[http.services.lg-server.loadBalancer.servers]]
        url = "http://localhost:5000/"

[docker]
  endpoint = "unix:///var/run/docker.sock"
  domain = "localhost"
  watch = true
  exposedbydefault = false

In the frontend/client, I have added in the package.json:

"proxy": "http://backend:5000"

When I hit docker-compose up --build, I can open my localhost:3000 correctly. localhost:5000/api/products also returns the right response.
However, localhost:3000/api/products doesn't. It returns my public/index.html!

It worked correctly before I dockerised my application and started using traefik, if I just have in the package.json:

"proxy": "http://localhost:5000"

Can someone help me with this please?

Your traefik is only bound to 80 (and 8080 for api insecure) so localhost:3000 will be going to your container direct per its 3000:3000 port option.

Additionally the router rules are incorrect as they do not have a router identifier:

- "traefik.http.routers.rule=Host:localhost"
# should have an identifier and the rule format is incorrect:
# written this way the router will only be accessible from the docker host
- "traefik.http.routers.foo.rule=Host:(`localhost`)"

service(aside from not having a router identifier) is not required as the container is the service

If the container does not EXPOSE a port in its docker file you may need:

- "traefik.http.service.foo.loadbalancer.server.port=3000"

This is not valid label, also 8080 is not defined as an entrypoint

If you are binding this router to an entrypoint:

# to use the defined web entrypoint
- "traefik.http.routers.foo.entrypoints=web"

Your trafik.toml contains both static config and dynamic provider, this need to be seperated into two file. And you load the dynamic file provider in the static config.

Using localhost as a backend server will not work, as that is the traefik container itself. You need to use a reachable address on the docker host.

Thanks so much for getting back to me with these answers, that's very helpful!!

I tried modifying my files accordingly but am still struggling to make it work properly. I realise there are some areas I didn't understand quite well enough...

When you say that, does it mean that in local I'm supposed to hit localhost:80 instead of localhost:3000 now that I'll use Traefik? Or should I define 3000 as an entrypoint? Or maybe use the host that I can see in the Traefik dashboard under "Used by Routers" (client-myapp)?

Where can I find this reachable address? Is it the one I can see in the Traefik dashboard in the server url of my server? http://192.168.208.2:5000?

Also, what am I supposed to see in the dashboard to make sure that my router is working correctly?
I'll be able to see the server, client and reverse-proxy in the services and router, but shouldn't I see that client -> reverse-proxy -> server ? or something like this?

What do you want to access it on? If you want to use traefik on port 80 then you will access it on localhost:80. The usual use case would be to use an entrypoint on 80 or 443.

That is probably the one. Or you can use the ip of the docker0 interface.
Also:

I guess I'm supposed to access it on port 3000?
For now, if I hit localhost:80, it returns a 404

For example if I look at this image here: https://docs.traefik.io/assets/img/entrypoints.png
the http://localhost:8081/ in my case is localhost:3000, so where can I define this entrypoint in traefik so that it goes in the router and when it sees that there is my domain=localhost + port=3000 + pathPrefix=/api it redirects to my backend with port=5000 ?

I tried defining this entrypoint in the traefik.toml but wonder now if I need to add the labels in the client service in docker as well? I find it a bit confusing to have traefik labels in docker + traefik config in the traefik.toml

That is because of the misconfiguration.

Are your trying to proxy your containers or are there actually other services running locally?

You don't need to, it depends on what your are doing. If you are routing to a service that is not a container in your docker (external service) the you do need to use a File Provider it may help cement some concepts.

Go and look at concepts and run through the Quick Start

I'm trying to proxy my containers.
In this case I might just remove this file provider indeed

I looked at the concepts and did the quick start on my machine but it's not obvious how to proxy from one container to another on a specific request.

I just would like to proxy to my server container when my client container does a request with /api

Personally I wouldn't use Traefik to address other containers but rather user docker networking.

If you are determined to do it you need to make sure that the Host you are using in the router rule is resolved by the container to the Traefik container. It would be easier NOT to use a Host rule in this case.

I see... Thank you very much for your help and advice!