Skip to main content

Traefik v2 Webproxy Configuration - 2nd Attempt

Central, Hong Kong

This guide is incomplete... Traefik, atm unfortunately, does not match my workflow. I am running into a lot of issues with the official documentation as well as the countless tutorials out there. I will put this project on hold until I figured it out.

I was following along the official Traefik Tutorials and ran into a couple of issues. So let's break this down a bit. I now started 3 Node.js web services that only return a string:

curl http://192.168.2.110:8300/
Server One

curl http://192.168.2.110:8301/
Server Two

curl http://192.168.2.110:8200/
Server Three

I will now start Traefik on a different server and want it to loadbalance my services.

Folders and Files

mkdir -p /opt/traefik/{certs,shared,rules}
touch /opt/traefik/traefik.log

Proxy Network

docker network create --gateway 192.168.144.1 --subnet 192.168.144.0/24 traefik_proxy

Static Configuration

/opt/traefik/traefik.yml

################################################################
# API and dashboard configuration
################################################################
api:
  # Dashboard
  dashboard: true
  insecure: true
################################################################
# Entrypoint
################################################################
entryPoints:
  web:
    address: ':80'
################################################################
# Docker configuration backend
################################################################
# providers:
#   docker:
#   watch: true
#   exposedByDefault: false
################################################################
# File configuration backend
################################################################
# providers:
#   file:
#     filename: services.yml
#     watch: true
################################################################
# Directory configuration backend
################################################################
providers:
  file:
    directory: /etc/traefik/services
    watch: true
################################################################
# Traefik Logging
################################################################
log:
  level: DEBUG # (Default: error) DEBUG, INFO, WARN, ERROR, FATAL, PANIC
accessLog:
  filePath: /traefik.log
  bufferingSize: 100 # Configuring a buffer of 100 lines
  filters:
    statusCodes: 400-499

Service Configuration

/opt/traefik/services.yml

http:
  routers:
    backendRouter:
      rule: Host(`192.168.2.111`)
      service: backendService

  services:
    backendService:
      loadBalancer:
        servers:
          - url: 'http://192.168.2.110:8300/'
          - url: 'http://192.168.2.110:8301/'
          - url: 'http://192.168.2.110:8200/'

Docker Compose

Create a docker-compose.yml file where you will define a reverse-proxy service that uses the official Traefik image:

version: '3'

networks:
  traefik_proxy:
    external:
      name: traefik_proxy
  default:
    driver: bridge

services:
  reverse-proxy:
    container_name: traefik
    restart: unless-stopped
    # The official v2 Traefik docker image
    image: traefik:latest
    ports:
      # Exposes port 81 for incoming web requests
      - '81:80'
      # The Web UI port http://0.0.0.0:8081
      - '8081:8080'
    networks:
      traefik_proxy:
        ipv4_address: 192.168.144.254
    volumes:
      # Let Traefik listen to the Docker events
      - /var/run/docker.sock:/var/run/docker.sock
      # Link log
      - /opt/traefik/traefik.log:/traefik.log
      # Link configuration
      - /opt/traefik/traefik.yml:/etc/traefik/traefik.yml
      - /opt/traefik/services.yml:/etc/traefik/services/services.yml
docker-compose up -d reverse-proxy

Check the API with jq (apt-get install jq):

curl http://localhost:8081/api/rawdata | jq

Traefik Detects New Services and Creates the Route for you. Add a web service to the docker-compose file and label it so it is picked up by Traefik:

whoami:
  # A container that exposes an API to show its IP address
  image: traefik/whoami
  networks:
    - traefik_proxy
  labels:
    - 'traefik.http.routers.whoami.rule=Host(`whoami.localhost`)'
docker-compose up -d whoami

The API now shows us that the Whoami Service is up and running;

curl http://localhost:8081/api/rawdata | jq

"whoami@docker": {
  "entryPoints": [
    "http"
  ],
  "service": "whoami-traefik",
  "rule": "Host(`whoami.localhost`)",
  "status": "enabled",
  "using": [
    "http"
  ]
}
curl -H Host:whoami.localhost http://127.0.0.1:8080

Hostname: 49323f79f37b
IP: 127.0.0.1
IP: 192.168.144.101
RemoteAddr: 192.168.144.254:42418
GET / HTTP/1.1
Host: whoami.localhost
User-Agent: curl/7.74.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 192.168.144.1
X-Forwarded-Host: whoami.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: 3a33e661f746
X-Real-Ip: 192.168.144.1

Traefik Load Balancing

Run more instances of your whoami service with the following command:

docker-compose up -d --scale whoami=2

We can now send two request and will get the replies from both instances in a RR fashion:

curl -H Host:whoami.localhost http://127.0.0.1:8080

Hostname: 51ba8be4f4ec
IP: 127.0.0.1
IP: 192.168.144.2


curl -H Host:whoami.localhost http://127.0.0.1:8080

Hostname: 749f615cab45
IP: 127.0.0.1
IP: 192.168.144.3

Basic Authentication

Logins in Docker-Compose File

services:
  reverse-proxy:
    container_name: traefik
    restart: unless-stopped
    image: traefik:v2.5
    ports:
      - '8080:80'
      - '8081:8080'
    networks:
      traefik_proxy:
        ipv4_address: 192.168.144.254
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /opt/traefik/traefik.log:/traefik.log
    command: # CLI arguments
      - '--api.insecure=true' # Traefik 2 dashboard authentication
      - '--providers.docker=true'
      - '--providers.docker.exposedbydefault=false'
      - '--providers.docker.network=default'
      - '--entrypoints.web.address=:80'
      - '--api'
      - '--log=true'
      - '--log.level=DEBUG' # (Default: error) DEBUG, INFO, WARN, ERROR, FATAL, PANIC
      - '--accessLog=true'
      - '--accessLog.filePath=/traefik.log'
      - '--accessLog.bufferingSize=100' # Configuring a buffer of 100 lines
      - '--accessLog.filters.statusCodes=400-499'
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)'
      - 'traefik.http.routers.http-catchall.entrypoints=web'
      # auth middleware with "test:test" or "test2:test2"
      - 'traefik.http.middlewares.my-auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0'

  whoami:
    image: traefik/whoami
    networks:
      - traefik_proxy
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.whoami.rule=Host(`whoami.localhost`)'
      - 'traefik.http.routers.whoami.entrypoints=web'
      # connect your auth middleware to a service which you want to protect
      - 'traefik.http.routers.whoami.middlewares=my-auth'

Test your configuration - accessing your service now requires a login:

curl -H Host:whoami.localhost http://127.0.0.1:8080
401 Unauthorized
curl -u test -H Host:whoami.localhost http://127.0.0.1:8080

Enter host password for user 'test':
Hostname: 8e1edc591948
IP: 127.0.0.1
IP: 192.168.144.2
RemoteAddr: 192.168.144.254:51444
GET / HTTP/1.1
Host: whoami.localhost
User-Agent: curl/7.74.0
Accept: */*
Accept-Encoding: gzip
Authorization: Basic dGVzdDp0ZXN0
X-Forwarded-For: 192.168.144.1
X-Forwarded-Host: whoami.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: a037bf49a135
X-Real-Ip: 192.168.144.1

External Password File

The usersFile option is the path to an external file that contains the authorized users for the middleware. Start by creating a .htpasswd file with the login credentials:

apt-get install apache2-utils
htpasswd -c /opt/traefik/shared/.htpasswd myuser

We now need to mount both our rule and the password file into the Traefik Docker container and make sure that Traefik actually uses these files:

services:
  reverse-proxy:
    container_name: traefik
    restart: unless-stopped
    image: traefik:v2.5
    ports:
      - '8080:80'
      - '8081:8080'
    networks:
      traefik_proxy:
        ipv4_address: 192.168.144.254
    volumes:
      - /opt/traefik/rules:/rules
      - /opt/traefik/shared:/shared
      - /var/run/docker.sock:/var/run/docker.sock
      - /opt/traefik/traefik.log:/traefik.log
    command: # CLI arguments
      - '--api.insecure=false' # Traefik 2 dashboard authentication
      - '--providers.docker=true'
      - '--providers.docker.exposedbydefault=true'
      - '--providers.docker.network=default'
      - '--entrypoints.web.address=:80'
      - '--api'
      - '--log=true'
      - '--log.level=ERROR' # (Default: error) DEBUG, INFO, WARN, ERROR, FATAL, PANIC
      - '--accessLog=true'
      - '--accessLog.filePath=/traefik.log'
      - '--accessLog.bufferingSize=100' # Configuring a buffer of 100 lines
      - '--accessLog.filters.statusCodes=400-499'
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)'
      - 'traefik.http.routers.http-catchall.entrypoints=web'
      # auth middleware with path to .htpasswd as mounted in volumes
      - 'traefik.http.middlewares.my-auth.basicauth.usersfile=/shared/.htpasswd'

  whoami:
    image: traefik/whoami
    networks:
      - traefik_proxy
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.whoami.rule=Host(`whoami.localhost`)'
      - 'traefik.http.routers.whoami.entrypoints=web'
      # connect your auth middleware to a service which you want to protect
      - 'traefik.http.routers.whoami.middlewares=my-auth'
curl -H Host:whoami.localhost http://127.0.0.1:8080
401 Unauthorized
curl -u myuser -H Host:whoami.localhost http://127.0.0.1:8080

Enter host password for user 'myuser':
Hostname: 8658cc0f5b2a
IP: 127.0.0.1
IP: 192.168.144.2
RemoteAddr: 192.168.144.254:54796
GET / HTTP/1.1
Host: whoami.localhost
User-Agent: curl/7.74.0
Accept: */*
Accept-Encoding: gzip
Authorization: Basic
X-Forwarded-For: 192.168.144.1
X-Forwarded-Host: whoami.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: c5f9a76e16e6
X-Real-Ip: 192.168.144.1