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