Use url to redirect to host service

Hello,
I'm trying to use traefik in docker compose to point to a service on my host that can't run in a docker. I have thus the following configuration

  harbor:
    image: alpine
    command: sleep infinity
    extra_hosts:
      - host.docker.internal:host-gateway
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.harbor.rule=Host(`harbor.example.com`)"
      - "traefik.http.routers.harbor.entrypoints=websecure"
      - "traefik.http.routers.harbor.tls.certresolver=myresolver"
      - "traefik.http.services.harbor.loadbalancer.server.url=http://host.docker.internal:8081"
      - "traefik.http.services.harbor.loadbalancer.server.port=8081"

That should simply point to a service on my host running on port 8081, but in the current state, a current request will never return and get a Gateway error. The port is allowed by the firewall

I already have multiple service in that swarm with traefik acting very well as a reverse proxy to add https and redirect based on the host. I saw in a recent PR that it's possible to use the url.
The port is supposed to be a dummy port because traefik will raise an error if I don't specify a port. I use traefik image 3.3 which is the latest

loadbalancer.server.url is not available with providers.docker and labels (reference), as the labels always target the service/container itself.

You need to use a dynamic config file.

Also note that host.docker.internal is only available with Docker Desktop.

You need to use the real host IP. Not localhost 127.0.0.1, as that is only localhost within the container itself.

I see,
I actually struggle to configure the dynamic configuration file. I use a volume that seems to do the trick but I get error="the service is missing on the router for the following configuration

http:
  routers:
    harbor:
      rule: "Host(`harbor.example.com`)"
      entryPoints:
        - websecure
      tls:
        certresolver: myresolver
  services:
    harbor:
      loadBalancer:
        servers:
          - url: "http://<ip>:8081"

Is there something I don't get ? The configuration looks a lot like the docker label configuration tho

says exactly what it means :wink:

There is no automatic assignment of a service to a router with the same name, so you need to add the assignment:

http:
  routers:
    harbor:
      rule: "Host(`harbor.example.com`)"
      entryPoints:
        - websecure
      tls:
        certresolver: myresolver
      service: harbor

oh yeah stupid mistake :') I didn't see that in the documentation. However it still seems that traefik doesn't find the service. A curl to that host doesn't return anything, the request seems to be dropped. I simply run a python http server to make the tests, and my traefik configuration is that

  reverse-proxy:
    image: traefik:v3.3
    command:
      - "--api.dashboard=true"
      - "--log.level=INFO"
      - "--providers.docker"
      - "--providers.docker.exposedbydefault=false"
      - "--entryPoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=pro@noahcode.dev"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
      - "--entryPoints.web.address=:80"
      - "--entryPoints.web.http.redirections.entrypoint.to=websecure"
      - "--entryPoints.web.http.redirections.entrypoint.scheme=https"
      - "--providers.file.directory=/traefik/dynamic/"
      - "--providers.file.watch=true"
    deploy:
      update_config:
        order: start-first
    ports:
      - mode: host
        protocol: tcp
        published: 80
        target: 80
      - mode: host
        protocol: tcp
        published: 443
        target: 443
    volumes:
      - letsencrypt:/letsencrypt
      - dynamic:/traefik/dynamic
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik

Is there something obvious I'm missing ?

Check Traefik debug log if the dynamic config file is loaded:

--log.level=DEBUG

It looks like there's no problem to me

> add watcher on: /traefik/dynamic/harbor.yaml
> Configuration received config={"http":{"routers":{"harbor":{"entryPoints":["websecure"],"rule":"Host(`harbor.example.com`)","service":"harbor","tls":{"certResolver":"myresolver"}}},"services":{"harbor":{"loadBalancer":{"passHostHeader":true,"responseForwarding":{"flushInterval":"100ms"},"servers":[{"url":"http://<ip>:8081"}]}}}},"tcp":{},"tls":{},"udp":{}} providerName=file
> Adding certificate for domain(s) harbor.example.com,open.example.com
> Configuration received config=[REDACTED] providerName=docker
> Creating load-balancer entryPointName=websecure routerName=harbor@file serviceName=harbor@file
> Creating server entryPointName=websecure routerName=harbor@file serverName=f17204525141416a serviceName=harbor@file target=http://<ip>:8081
> Adding route for harbor.example.com with TLS options default entryPointName=websecure
> Adding certificate for domain(s) harbor.example.com,open.example.com
> Trying to challenge certificate for domain [harbor.example.com] found in HostSNI rule ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=myresolver.acme routerName=harbor@file rule=Host(`harbor.example.com`)
> Looking for provided certificate(s) to validate ["harbor.example.com"]... ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=myresolver.acme routerName=harbor@file rule=Host(`harbor.example.com`)
> Creating load-balancer entryPointName=websecure routerName=harbor@docker serviceName=harbor@docker
> Creating server entryPointName=websecure routerName=harbor@docker serverName=aa6bf9240a2af4a3 serviceName=harbor@docker target=http://10.0.2.13:8081
> Creating load-balancer entryPointName=websecure routerName=harbor@file serviceName=harbor@file
> Creating server entryPointName=websecure routerName=harbor@file serverName=f17204525141416a serviceName=harbor@file target=http://<ip>:8081
> Adding route for harbor.example.com with TLS options default entryPointName=websecure
> Trying to challenge certificate for domain [harbor.example.com] found in HostSNI rule ACME 
CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=myresolver.acme routerName=harbor@docker rule=Host(`harbor.example.com`)
> Trying to challenge certificate for domain [harbor.example.com] found in HostSNI rule ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=myresolver.acme routerName=harbor@file rule=Host(`harbor.example.com`)
> No ACME certificate generation required for domains ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory domains=["harbor.example.com"] providerName=myresolver.acme routerName=harbor@file rule=Host(`harbor.example.com`)
> Looking for provided certificate(s) to validate ["harbor.example.com"]... ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=myresolver.acme routerName=harbor@docker rule=Host(`harbor.example.com`)
> No ACME certificate generation required for domains ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory domains=["harbor.example.com"] providerName=myresolver.acme routerName=harbor@docker rule=Host(`harbor.example.com`)
> Looking for provided certificate(s) to validate ["harbor.example.com"]... ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory providerName=myresolver.acme routerName=harbor@file rule=Host(`harbor.example.com`)
> No ACME certificate generation required for domains ACME CA=https://acme-v02.api.letsencrypt.org/directory acmeCA=https://acme-v02.api.letsencrypt.org/directory domains=["harbor.example.com"] providerName=myresolver.acme routerName=harbor@file rule=Host(`harbor.example.com`)

Check Traefik access log in JSON format during requests (doc):

--accesslog.format=json

Ok I got it work. This really helped me debug. My final configuration is the following if someone needs it

services:
  reverse-proxy:
    image: traefik:v3.3
    command:
      - "--api.dashboard=true"
      - "--log.level=DEBUG"
      - "--accesslog.format=json"
      - "--providers.docker"
      - "--providers.docker.exposedbydefault=false"
      - "--entryPoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=pro@example.com"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
      - "--entryPoints.web.address=:80"
      - "--entryPoints.web.http.redirections.entrypoint.to=websecure"
      - "--entryPoints.web.http.redirections.entrypoint.scheme=https"
      - "--providers.file.directory=/traefik/dynamic/"
      - "--providers.file.watch=true"
    deploy:
      update_config:
        order: start-first
    ports:
      - mode: host
        protocol: tcp
        published: 80
        target: 80
      - mode: host
        protocol: tcp
        published: 443
        target: 443
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - letsencrypt:/letsencrypt
      - dynamic:/traefik/dynamic
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik

http:
  routers:
    harbor:
      rule: "Host(`harbor.example.com`)"
      entryPoints:
        - websecure
      tls:
        certresolver: myresolver
      service: harbor
  services:
    harbor:
      loadBalancer:
        servers:
          - url: "http://host.docker.internal:8081"

Thank you for your help !

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.