API not accessible when Traefik in host network mode

I am running Traefik on a simple single-node docker host. I had a successful configuration in the past with port-forwarding, but decided to let Traefik run with host network mode to get useful source IP addresses, for example for fail2ban.

Problem is: After switching Traefik to host network, i cannot access its dashboard and API, and am struggling to find out why.

Currently i have this in my compose file for traefik itself:

    labels:
      traefik.enable: "true"
      traefik.http.routers.api.rule: "Host(`traefik.{{ traefik_domain }}`)"
      traefik.http.routers.api.entrypoints: "https"
      traefik.http.routers.api.middlewares: "auth@file"
      traefik.http.routers.api.service: "api@internal"
      traefik.http.routers.api.tls.certresolver: "le"

This is a snippet from my traefik.yaml:

entryPoints:
  http:
    address: ":80"
  https: 
    address: ":443"
  traefik:
    address: ":8082"

The dashboard is currently accessible via http://hostip:8082, but i want traefik to have a route to itself, for middlewares, TLS handling and so on.
I have some other services on the same host with host networking, which have a similar config in their compose files, which are still accessible, so i'm wondering why the API behaves differently.

What is working, however, is to not define the service as api@internal but with the following settings:

      traefik.http.routers.api.rule: "Host(`traefik.{{ traefik_domain }}`)"
      traefik.http.routers.api.entrypoints: "https"
      traefik.http.routers.api.middlewares: "auth@file"
      traefik.http.routers.api.service: "api"
      traefik.http.routers.api.tls.certresolver: "le"
      traefik.http.services.api.loadbalancer.server.port: "8082"

So not letting traefik access itself internally but accessing the host network address on port 8082 which is the entrypoint for the API. Why is it like that, that its not possible to access traefik internally when its running in host network mode?

1 Like

Updating everyone with my configuration, which is like OP’s - single docker host. Traefik does a lot automatically so you can really simplify your configurations.

First, my docker-compose.yml which I use to manually docker compose up -d when I need to upgrade Traefik:

services:
  traefik:
    # The official Traefik docker image
    image: traefik:3.4.4
    hostname: traefik
    restart: unless-stopped
    ports:
      # web, redirect to websecure only
      - "80:80"
      # websecure
      - "443:443"

    volumes:
      # Listen for docker events
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      # Store some data on the host
      - "/home/docker/traefik/config/:/etc/traefik/:rw"
      - "/home/docker/traefik/log/:/var/log/traefik:rw"
      # Take host's timezone
      - "/etc/timezone:/etc/timezone:ro"
      - "/etc/localtime:/etc/localtime:ro"

    labels:
      - "traefik.http.routers.dashboard.rule=Host(`traefik.[my container subdomain]`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
      - "traefik.http.routers.dashboard.service=api@internal"

In that /config directory is traefik.yml:

################################################################
# Global configuration
################################################################
global:
  checkNewVersion: true
  sendAnonymousUsage: true

################################################################
# EntryPoints configuration
################################################################

# Default entry point for the LAN.

entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: "websecure"

  websecure:
    address:	:443
    asDefault: true
    http:
      tls: {}
      # See ./config/dyn-conf/tls.yml


################################################################
# Traefik logs configuration
################################################################

# Traefik logs
# Enabled by default and log to stdout
#
# Optional
#
log:
  # Log level
  #
  # Optional
  # Default: "ERROR"
  #
  level: INFO

  # Sets the filepath for the traefik log. If not specified, stdout will be used.
  # Intermediate directories are created if necessary.
  #
  # Optional
  # Default: os.Stdout
  #
#  filePath: log/traefik.log
  # filePath: /var/log/traefik/info.log

  # Format is either "json" or "common".
  #
  # Optional
  # Default: "common"
  #
#  format: json

################################################################
# Access logs configuration
################################################################

# Enable access logs
# By default it will write to stdout and produce logs in the textual
# Common Log Format (CLF), extended with additional fields.
#
# Optional
#
# accessLog: {}
  # Sets the file path for the access log. If not specified, stdout will be used.
  # Intermediate directories are created if necessary.
  #
  # Optional
  # Default: os.Stdout
  #
#   filePath: /var/log/traefik/access.log
#   bufferingSize: 25
#   fields:
#     headers:
#       defaultMode: keep
#   filters:
#     statusCodes:
# #       - "100-199"
#       - "300-399"
#       - "400-499"
#       - "500-599"

  # Format is either "json" or "common".
  #
  # Optional
  # Default: "common"
  #
#  format: json

################################################################
# API and dashboard configuration
################################################################

# Enable API and dashboard
#
# Optional
#
api:
  # Enable the API in insecure mode
  #
  # Optional
  # Default: false
  #
#  insecure: true

  # Enabled Dashboard
  #
  # Optional
  # Default: true
  #
  dashboard: true

################################################################
# Ping configuration
################################################################

# Enable ping
ping:
  # Name of the related entry point
  #
  # Optional
  # Default: "traefik"
  #
  # entryPoint: websecure

################################################################
# Docker configuration backend
################################################################

providers:
  # Enable Docker configuration backend
  docker:
    # Docker server endpoint. Can be a tcp or a unix socket endpoint.
    #
    # Required
    # Default: "unix:///var/run/docker.sock"
    #
    #    endpoint:

    # Default host rule.
    #
    # Optional
    # Default: "Host(`{{ normalize .Name }}`)"
    #
    defaultRule: Host(`{{ normalize .Name }}.[my container subdomain]`)

    # Expose containers by default in traefik
    #
    # Optional
    # Default: true
    #
    #    exposedByDefault: false

    # network
    # 
    # Optional, Default=""
    # 
    # Defines a default docker network to use for connections to all containers.
    # 
    # This option can be overridden on a per-container basis with the traefik.docker.network label.
    network: traefik_default

  # Dynamic configuration file watch
  # Note: "/home/docker/traefik/config/:/etc/traefik/:rw"
  file:
    directory: /etc/traefik/dyn-conf
    watch: true

In my dynamic config, I have tls.yml defining the wildcard certificate I manually created for Traefik.

tls:
  certificates:
    - certFile: /etc/traefik/services.crt
      keyFile: /etc/traefik/services.key

That’s the bulk to setting up Traefik as a secure SSL terminating reverse proxy.

Edit: Consider your security position when you mount the docker socket as I did in the example above. While this is the default configuration offered by Traefik, they also have a section in the docs dedicated to securing the Docker API access if that’s a concern for you. Be extra careful if any of your services will be exposed to the Internet.

1 Like

Note that :ro does not work for sockets, I always feel this implies a false sense of security.

If you want to protect your Docker socket, which makes sense, you need to use some kind of Docker socket proxy, for example to disable POSTs.

But please don’t just install a random image from the Internet when trying to improve security of your setup :upside_down_face:

Not downloading random images from the Internet is good advice in general :grinning_face:

I’ll leave a link above to Traefik’s docs on using and securing the Docker API access. Definitely worth considering.