Forwarding one Traefik endpoint to dockers host network

Hi I am new to Docker and Traefik. I have a few containers installed and all of them are opened thru Traefik to the outside world.

I recently wanted to run a Home Assistant (http://home-assistant.io) at home as well in a docker container but I am running in to issues there. I am hoping someone would help as I have been spending a lot of time trying to get it to work and just not having much luck.

The issue is Home Assistant requires to be in the host network to discover things and communicate with them so when I setup in host mode I need traefik to send the port 8123 to my host network or to my host IP (I can open the 8123 port for home assistant).

I posted this question in home assistant as well but I think it is more appropriate to seek help here in this subject. Here is the details for my compose files:

I am trying to setup Home Assistant behind traefik inside a docker container.
My primary use case is:

  1. Add Garage and Lights to HA (they cannot connect to directly to Google Assistant)
  2. Setup Google Assistant to connect to HA
  3. Control Garage and Lights with Google Assistant

in Docker host_mode - #1 works, no problems with discovery etc. but I cannot send port 80 traefik to host mode since traefik is inside a private network. So can't get Google to work
in docker-network mode - #1 wont work because the devices Ip are in a different subnet in host network.

My question is if I setup HA in host networking mode how can I redirect traffic from outside world to that container when traefik is defined in a separate network inside docker?

I read this link which talks about similar problem but I tried the suggested solutions and none of them worked for me so I thought I would post my configurations and see if someone can help me.

traefik compose :

version: "3.3"
services:
  traefik:
    image: traefik:latest
    container_name: "traefik"
    restart: always
    command:
      - "--global.sendAnonymousUsage=false"
      - "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.httpchallenge=true"
      - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.myresolver.acme.email=myemail"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
      - "--entrypoints.websecure.http.middlewares=sts"
    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik.middlewares=auth
      - traefik.http.middlewares.sts.headers.stspreload=true
      - traefik.http.middlewares.sts.headers.stsseconds=31536000
    ports:
      - "80:80"
      - "443:443"
    networks:
      docker-network:
        aliases:
          - traefik
    volumes:
      - ".traefik_data/:/letsencrypt"
      - "./traefik_data/.htpasswd:/auth/.htpasswd"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
  docker-network:
    external: true

I also have single sign on enabled using this container below which redirects traffic to the appropriate container/ sub-domain
traefik-auth compose:

version: "3.3"
services:
  traefik-forward-auth:
    image: thomseddon/traefik-forward-auth:2.1-arm
    container_name: "traefik-auth"
    restart: always
    environment:
      - DEFAULT_PROVIDER=oidc
      - PROVIDERS_OIDC_ISSUER_URL=https://login.microsoftonline.com/{tenant-id}/v2.0
      - PROVIDERS_OIDC_CLIENT_ID={clientid}
      - PROVIDERS_OIDC_CLIENT_SECRET={secret}
      - SECRET={secret}
      - DOMAIN={my domain name}
      - LOG_LEVEL=debug
      - AUTH_HOST=traefik-forward-auth.{my domain name}
    networks:
      docker-network:
        aliases:
          - traefik-auth
    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik-forward-auth.middlewares=auth
      - traefik.http.routers.traefik-forward-auth.entrypoints=websecure
      - traefik.http.services.traefik-forward-auth.loadbalancer.server.port=4282
      - traefik.http.middlewares.auth.forwardauth.address=http://traefik-forward-auth:4282
      - traefik.http.middlewares.auth.forwardauth.authresponseheaders=X-Forwarded-User
networks:
  docker-network:
    external: true

finally my home assistant compose:

version: '3'
services:
  homeassistant:
    container_name: homeassistant
    image: homeassistant/home-assistant:stable
    networks:
      docker-network:
        aliases:
          - homeassistant
    ports: 
      - 8123:8123
    volumes:
      - .homeassistant_data:/config
    restart: always
    labels:
      - "traefik.enable=true"
      - "traefik.port=8123"
      - "traefik.http.middlewares.ha.redirectscheme.scheme=https"
      - "traefik.http.routers.ha.middlewares=auth"
      - "traefik.http.routers.ha-insecure.rule=Host(`hassio.{my domain name}`)"
      - "traefik.http.routers.ha-insecure.middlewares=ha"
      - "traefik.http.routers.ha.rule=Host(`hassio.{my domain name}`)"
      - "traefik.http.routers.ha.entrypoints=websecure"
      - "traefik.http.routers.ha.tls.certresolver=myresolver"
      - "traefik.http.services.ha.loadBalancer.server.port=8123"

networks:
  docker-network:
    external: true

Anyone out there to help me with this? Been scratching my head for a few days and going crazy now. :-/ @trajano @ldez sorry to bother you but you seem active on the forums maybe take a quick peek? :slight_smile:

From what I understand, you're attempting to use traefik to handle routing for a service that is running in host network mode. The reason why this won't work without additional configuration (as I understand) is that this takes the service out of the network plane which traefik relies on for discovery and routing.

You may be able to solve this issue by defining a file provider which routes to the host network for your HA service. This answer on SO should be able to help you understand how to implement this solution: https://stackoverflow.com/questions/46245684/how-to-get-traefik-to-redirect-to-specific-non-docker-port-from-inside-docker

@notsureifkevin thank you for that link and taking the time to post, i truly appreciate it.
i tried creating a file just for [file] providers and i am getting error as below. but I also tried moving everything from compose to command and got a lot of errors there that is beyond me.

traefik.toml: 
[file]
        filename = "servers.toml"
# Enable watch file changes
        watch = true

servers.toml file:

loglevel = "ERROR"
[backends]
[backends.nasweb]
        [backends.nasweb.servers.nasweb]
            url = "http://192.168.1.200:8080"
[frontends]
        [frontends.domain]
                backend = "nasweb"
        [frontends.domain.routes.domain]
                rule = "Host:abc.domain.com"

error when container is started:

command traefik error: no valid configuration found in file: /etc/traefik/traefik.toml 

Hi @Crossrock , happy to try and help on this one. It looks like you're trying to incorporate the config schema that is valid for v1.7 of traefik, however, you're using 2.x in your example. There is an answer in that SO post a bit further down that should get you pointed in the right direction.

Ty, Just tried the second option in the SO post. Looks like traefik is not throwing errors but i am getting a 404 page not found error. Just to clarify, the traefik container is in private network whereas i am trying to redirect the url to the host or another in in my host network. Could it be because of the traefik auth container ? But I don’t have any labels for that in the providers file so it shouldn’t impact i think?
Is there a way to check where the domain is pointing to the local lan? I am not seeing anything in traefik debug mode.

Here is my rules.toml:

 [http.routers]
   # Define a connection between requests and services
     [http.routers.nasweb]
        rule = "Host(`subdomain.domain.com`)"
        entrypoints = ["websecure"]
        service = "nas"
     [http.routers.nasweb.tls]
        certResolver = "myresolver"
 [http.services]
        # Define how to reach an existing service on our infrastructure
        [http.services.nas.loadBalancer]
           [[http.services.nas.loadBalancer.servers]]
             url = "http://LAN-IP-OF-PC-IN-HOST-Network:7878"

I added these to my traefik.yml in the first post:

      - "--providers.file=true"
      - "--providers.file.filename=/etc/traefik/rules.toml"

I see in the traefik logs the rules file was processed so i think i am getting close...
one thing to note though, when i add the host ip address and port 8123 above it gives me bad gateway and when i added a PC in my network I get 404 error even though the site works at that destination with local ip.

I'm not too familiar with how the traffic is handled with regards to the authentication for OIDC, unfortunately.

I was able to get the file provider to work by providing a real IP for my local host ip address (this is the one which was assigned by my DHCP server). You can also get this IP by exec'ing into your HA server and running the command: route | awk '/^default/ { print $2 }'

If this works, you may want to consider assigning a static IP to the host you're running these containers on.

I think you are right. The traefik dashboard shows middleware "sts@file" does not exist.

when I run the command you sent, it returns my gateway / router IP address actually and not the local host IP address. My Local host already has static IP assigned.

Where have you defined the sts middleware? Perhaps others in the community may have a better idea of how that would work.

I assume you discovered that by changing the url = "http://LAN-IP-OF-PC-IN-HOST-Network:7878" to http://<actual_host_ip>:8123 traefik stopped sending you Bad Gateway

the sts headers are defined in the traefik compose as labels

    labels:
      - traefik.enable=true
      - traefik.http.routers.traefik.middlewares=auth
      - traefik.http.middlewares.sts.headers.stspreload=true
      - traefik.http.middlewares.sts.headers.stsseconds=31536000

yes, I found the bad gateway and 404 error by changing the ipaddress in the rules.toml to HA container to an IP on my network

Thank you for you r help @notsureifkevin i was able to finally get it working. Appreciate your help. That SO link was very helpful.

1 Like

@Crossrock Would you be willing to share your configuration? I'm in the same boat you're in and am looking for a solution.

EDIT: Figured it out. Thank you for asking the right question, and saying you got it working.

For the next guy:

https://stackoverflow.com/questions/46245684/how-to-get-traefik-to-redirect-to-specific-non-docker-port-from-inside-docker had the required information.

this is what my rules.toml looked like after modifying (not shown: referenced changes to docker-compose file)


 [http.routers]
   # Define a connection between requests and services
     [http.routers.hass]
        rule = "Host(`yourdomain.tld`)"
        entrypoints = ["websecure"] 
        service = "hass"
     [http.routers.hass.tls]
        certResolver = "le"


 [http.services]
        # Define how to reach an existing service on our infrastructure
        [http.services.hass.loadBalancer]
           [[http.services.hass.loadBalancer.servers]]
             url = "http://[INTERNAL_IP_OF_HASS:8123"

Change: yourdomain.tld to your domain, and INTERNAL_IP_OF_HASS:8123 to your internal IP for home assistant.

2 Likes

Hi,

I have the same problem where I would like traefik to redirect traffic to a container launched by docker-compose in network mode.

So when someone types the url $FQDN/PatientManager, it should redirect to the container named 'gazelle-patient-manager' on port 8080.

Currently, here is the configuration of the 'gazelle-patient-manager' container:

  • docker-compose.yaml
version: '2.4'

volumes:
  gazelle-data:
    external: true

services:
   gazelle-patient-manager:
     container_name: gazelle-patient-manager
     #hostname: gazelle-patient-manager
     image: ${REGISTRY_APP}/app/gazelle-patient-manager:9.12.0
     volumes:
       - "/etc/timezone:/etc/timezone:ro"
       - "/etc/localtime:/etc/localtime:ro"
       - "/etc/letsencrypt:/etc/letsencrypt:ro"
       - "gazelle-data:/opt"
     env_file:
       - .env
     restart: always
     mem_limit: ${MEM_LIMIT}
     mem_reservation: ${MEM_RESERVATION}
     #cpus: '1'
     healthcheck:
       test: ["CMD", "curl", "-f", "http://localhost:8080${APP_URL_PATH_1}/home.seam"]
       interval: 1m30s
       timeout: 10s
       retries: 3
       start_period: 70s
     network_mode: "host"
     labels:
       - traefik.enable=true
       - traefik.http.routers.gazelle-patient-manager-http.entrypoints=insecure
       - traefik.http.routers.gazelle-patient-manager-http.rule=Host(`${FQDN}`) && PathPrefix(`${APP_URL_PATH_1}`)
       - traefik.http.routers.gazelle-patient-manager-http.service=gazelle-patient-manager
       - traefik.http.services.gazelle-patient-manager.loadbalancer.server.port=8080
       - traefik.http.services.gazelle-patient-manager.loadbalancer.server.url=http://${FQDN}:8080
       - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
       - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
       - traefik.http.routers.gazelle-patient-manager-http.middlewares=SecHeader@file
       - traefik.http.routers.gazelle-patient-manager-http.middlewares=https-redirect@docker
       - traefik.http.routers.gazelle-patient-manager-https.entrypoints=secure
       - traefik.http.routers.gazelle-patient-manager-https.rule=Host(`${FQDN}`) && PathPrefix(`${APP_URL_PATH_1}`)
       - traefik.http.routers.gazelle-patient-manager-https.tls=true
       - traefik.http.routers.gazelle-patient-manager-https.middlewares=SecHeader@file
       - net.ihe.gazelle.db.name=${DB_NAME}
     logging:
       options:
         max-size: "${MAX_SIZE}"
         max-file: "${MAX_FILE}"

And my traefik configuration:

  • docker-compose.yaml
version: '2.4'

services:
   gazelle-reverse-proxy:
     container_name: gazelle-reverse-proxy
     hostname: gazelle-reverse-proxy
     image: traefik:2.3.1
     volumes:
       - "/etc/timezone:/etc/timezone:ro"
       - "/etc/localtime:/etc/localtime:ro"
       - "/var/run/docker.sock:/var/run/docker.sock:ro"
       - "/etc/letsencrypt/:/etc/letsencrypt/:ro"
       - "${HOME}/configuration/gazelle-reverse-proxy/config/:/etc/traefik/config"
     restart: unless-stopped
     ports:
      - 80:80
      - 443:443
     mem_limit: ${MEM_LIMIT}
     mem_reservation: ${MEM_RESERVATION}
     #cpus: '1'
     env_file:
       - .env
     healthcheck:
       test: ["CMD", "traefik", "healthcheck", "--ping"]
       interval: 1m00s
       timeout: 10s
       retries: 3
       start_period: 15s
     labels:
       # Dashboard
       - traefik.enable=true
       - traefik.http.routers.gazelle-reverse-proxy-http.entrypoints=insecure
       - traefik.http.routers.gazelle-reverse-proxy-http.rule=Host(`traefik.${FQDN}`) && (PathPrefix(`${APP_URL_PATH_1}`) || PathPrefix(`${APP_URL_PATH_2}`))
       - traefik.http.routers.gazelle-reverse-proxy-http.service=api@internal
       - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
       - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
       - traefik.http.routers.gazelle-reverse-proxy-http.middlewares=SecHeader@file
       #- traefik.http.routers.gazelle-reverse-proxy-http.middlewares=auth@file
       - traefik.http.routers.gazelle-reverse-proxy-http.middlewares=https-redirect@docker
       - traefik.http.routers.gazelle-reverse-proxy-https.entrypoints=secure
       - traefik.http.routers.gazelle-reverse-proxy-https.rule=Host(`traefik.${FQDN}`) && (PathPrefix(`${APP_URL_PATH_1}`) || PathPrefix(`${APP_URL_PATH_2}`))
       - traefik.http.routers.gazelle-reverse-proxy-https.service=api@internal
       - traefik.http.routers.gazelle-reverse-proxy-https.tls=true
       - traefik.http.routers.gazelle-reverse-proxy-https.middlewares=SecHeader@file
       #- traefik.http.routers.gazelle-reverse-proxy-https.middlewares=auth@file
     logging:
       options:
         max-size: "${MAX_SIZE}"
         max-file: "${MAX_FILE}"
  • .env (for TRAEFIK_*)
[...]
TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT="false"
TRAEFIK_PROVIDERS_FILE_WATCH="true"
TRAEFIK_PROVIDERS_FILE_DIRECTORY="/etc/traefik/config/"
TRAEFIK_TRACING_ELASTIC="false"
TRAEFIK_ENTRYPOINTS_SECURE="true"
TRAEFIK_PROVIDERS_DOCKER_ENDPOINT="unix:///var/run/docker.sock"
TRAEFIK_PROVIDERS_DOCKER_SWARMMODE="false"
TRAEFIK_TRACING_ELASTIC_SERVICEENVIRONMENT=""
TRAEFIK_PING="true"
TRAEFIK_API="true"
TRAEFIK_GLOBAL_CHECKNEWVERSION="true"
TRAEFIK_TRACING_ELASTIC_SERVERURL=""
TRAEFIK_GLOBAL_SENDANONYMOUSUSAGE="false"
TRAEFIK_DEFAULT_ENTRYPOINTS="secure"
TRAEFIK_LOG_LEVEL="info"
TRAEFIK_TRACING_ELASTIC_SECRETTOKEN=""
TRAEFIK_TRACING="false"
TRAEFIK_LOG_FORMAT="common"
TRAEFIK_TRACING_SERVICENAME="gazelle-reverse-proxy"
TRAEFIK_ENTRYPOINTS_SECURE_ADDRESS=":443"
TRAEFIK_LOG="true"
TRAEFIK_ENTRYPOINTS_INSECURE_ADDRESS=":80"
TRAEFIK_ENTRYPOINTS_INSECURE="true"
TRAEFIK_PROVIDERS_DOCKER_WATCH="true"
TRAEFIK_PROVIDERS_DOCKER="true"
[...]
  • config/dynamic.yaml
tls:
  certificates:
    - certFile: /etc/letsencrypt/live/{{env "FQDN"}}/fullchain.pem
      keyFile: /etc/letsencrypt/live/{{env "FQDN"}}/privkey.pem
      stores:
        - default
    - certFile: /etc/letsencrypt/live/traefik.{{env "FQDN"}}/fullchain.pem
      keyFile: /etc/letsencrypt/live/traefik.{{env "FQDN"}}/privkey.pem
      stores:
        - default
  stores:
    default:
      defaultCertificate:
        certFile: /etc/letsencrypt/live/{{env "FQDN"}}/fullchain.pem
        keyFile: /etc/letsencrypt/live/{{env "FQDN"}}/privkey.pem

  options:
    default:
      minVersion: VersionTLS12
      sniStrict: false
  • config/middlewares
http:
  middlewares:
    SecHeader:
      headers:
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsSeconds: 31536000
        sslRedirect: true
        sslForceHost: true
        #sslHost: '{{env "FQDN"}}'
        #contentSecurityPolicy: "script-src 'self'; img-src 'self'"
        referrerPolicy: "same-origin"
        #featurePolicy: "vibrate 'self'; geolocation 'self'; midi 'self'; notifications 'self'; push 'self'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; vibrate 'self'; fullscreen 'self'"
        frameDeny: false
        contentTypeNosniff: true
        browserXssFilter: true

No error appears in traefik log and all seem be ok in traefik dashboard:

Can you help me to solve my problem ?

Thx in advance

Benjamin.

Hi,

Any idea to help me ? :slight_smile:

Have you tried adding the rules for forwarding in rules.toml? That’s how I got mine working. In the stackoverflow link above there is an example.