Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Getting Started With Traefik

This tutorial will show you how to get started with using Traefik locally, so that you can get to grips with it, before you dive into doing something more complicated, such as use it in a Kubernetes or Docker-Swarm cluster.

Related Posts

Table Of Contents

What is Traefik?

Traefik is a popular reverse proxy and load balancer that makes deploying microservices easy. This starts becoming essential quite quickly when you have a lot of web services that want to be accessed on ports 80/443. Traefik can also be quite handy at being the handler and termination point for SSL, so that your underlying services do not need to worry about them.

You can read more about it on their website.

Deploying Traefik

Static Config File

Before doing anything, you probably want to download the sample static config file, and call it static-config.yml, and uncomment most of it, applying settings that you want. I found that not doing so (expecting the defaults), resulted in the image not working.

You can download the sample from the website, or you can copy my example below:

################################################################
#
# Configuration sample for Traefik v2.
#
# For Traefik v1: https://github.com/traefik/traefik/blob/v1.7/traefik.sample.toml
#
################################################################

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

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

# EntryPoints definition
#
# Optional
#
entryPoints:
  web:
    address: :80

  websecure:
    address: :443

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

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

  # 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

  # 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: log/traefik-access.log

  # 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: traefik

################################################################
# 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: "unix:///var/run/docker.sock"

    # Default host rule.
    #
    # Optional
    # Default: "Host(`{{ normalize .Name }}`)"
    #
#    defaultRule: Host(`{{ normalize .Name }}.docker.localhost`)

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

We call it static-config.yml rather than traefik.yml to save confusion later when we will need to create other configuration files. This config file relates to anywhere in the documentation where it refers to "static" configuration, rather than something like "dynamic".

Create Network

Next, we want to create a network that Traefik will run on, that other services can later join, for which Traefik will act as a reverse proxy:

docker network create traefik-net

Deploy Traefik Container

Now we are ready to deploy Traefik. Here we will run the image, using the static-config.yml config file we created earlier.

docker run \
  --name traefik \
  --detach \
  --network traefik-net \
  --publish 8080:8080 \
  --publish 80:80 \
  --volume $PWD/static-config.yml:/etc/traefik/traefik.yml \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  traefik:v2.8
  • By using the static config file, we don't need to override the command/entrypoint like other tutorials do.
  • Using a volume for the Docker socket, allows Traefik to listen to events, so it can pick up on Docker events when other containers get deployed. This allows it to then automatically act as their reverse proxy.
  • The dashboard is exposed on port 8080, whereas port 80 is used for the "insecure" web connections.

Docker Compose Example

The Docker Compose equivalent is below if you need it:

version: "3.9"

networks:
  traefik-net:
    external: true

services:
  reverse-proxy:
    container_name: traefik
    image: traefik:v2.8
    networks:
      - traefik-net
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - ./static-config.yml:/etc/traefik/traefik.yml:ro # Provide the config file.
      - /var/run/docker.sock:/var/run/docker.sock # So that Traefik can listen to the Docker events

Dashboard

If you go to localhost:8080 in your browser, you should now see a dashboard for managing Traefik (if you used the same configuration settings, whereby the dashboard was enabled).

Deploy Example Web Service

Now lets test it by deploying an example web service that wants to be exposed on port 80.

docker run \
  --detach \
  --name whoami1 \
  --network traefik-net \
  --label "traefik.http.routers.whoami.rule=Host(\"whoami.docker.localhost\")" \
  traefik/whoami
  • The key thing here is the --label. This tells Traefik that this container wants to be served up, when a request comes in for whoami.docker.localhost.
  • The --network traefik-net tells the container to join the traefik-net network that you created earlier, allowing Traefik to communicate with the container.

Docker Compose Example

The Docker Compose equivalent is below if you need it.

version: "3.9"

networks:
  traefik-net:
    external: true

services:
  whoami:
    container_name: whoami
    image: traefik/whoami
    networks: 
      - traefik-net
    labels:
      - traefik.http.routers.whoami.rule=Host("whoami.docker.localhost")

Make sure to have this in a different folder to the compose file for Traefik, otherwise you get int "orphaned container" and project naming issues.

Check It Works

Now if you go to whoami.docker.localhost in your web browser, you should see some output from the whoami service similar to below:

Hostname: ff8f10b92857
IP: 127.0.0.1
IP: 172.31.0.3
RemoteAddr: 172.31.0.2:56022
GET / HTTP/1.1
Host: whoami.docker.localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en;q=0.5
Dnt: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Sec-Gpc: 1
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 172.31.0.1
X-Forwarded-Host: whoami.docker.localhost
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: cbfbb38ae0b0
X-Real-Ip: 172.31.0.1

Configure Wildcard Certificate

If you generate your own wildcard certificate for your domain, one can configure Traefik to use it as the fallback/default for TLS connections.

Create The Dynamic Config File

First, we need to create a dynamic-config.yml file that specifies the path to where the TLS certificates will be inside the container. In this case, I am calling them wildcard.crt for the certificate "bundle", and private.pem for the private key.

tls:
  stores:
    default:
      defaultCertificate:
        certFile: /ssl/wildcard.crt
        keyFile: /ssl/private.pem

Add File Provider To Static Config

Update the static-config.yml file to add a "file provider" (which is our `dynamic-config.yml file).

# ...
providers:
  docker:
    endpoint: unix:///var/run/docker.sock
    exposedByDefault: true
  file:
    directory: /etc/traefik/dynamic

Update Traefik Docker Compose

Now update the docker-compose.yml file to:

  • listen for port 443
  • Provide the dynamic-config.yml dynamic configuration file through a read-only volume.
  • Provide the certificates through a read-only volume (in this case a folder called ssl at the same level as the docker-compose.yml file).
version: "3.9"

networks:
  traefik-net:
    external: true

services:
  reverse-proxy:
    container_name: traefik
    image: traefik:v2.8
    networks:
      - traefik-net
    ports:
      - "80:80" # "web" HTTP listener
      - "443:443" # "websecure" SSL listener
      - "8080:8080" # Traefik dashboard
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock # Allows Traefik to listen to the Docker events
      - ./static-config.yml:/etc/traefik/traefik.yml:ro # Provide the static config file.
      - ./dynamic-config.yml:/etc/traefik/dynamic/conf.yml:ro # Provide the dynamic config file (SSL)
      - ./ssl:/ssl:ro # Wildcard default SSL certificate referenced in dynamic-config.yml

If need be, you can refer to the relevant area of the official documentation.

Update Web Service Labels

Finally, we need to update the labels on the web services we deploy, to specify the routing for TLS connections on the websecure endpoint.

version: "3.9"

networks:
  traefik-net:
    external: true

services:
  whoami:
    container_name: whoami
    image: traefik/whoami
    networks: 
      - traefik-net
    labels:
      # Specify http routing
      - traefik.http.routers.whoamihttp.entrypoints=web
      - traefik.http.routers.whoamihttp.rule=Host("whoami1.programster.org")
      - traefik.http.routers.whoamihttp.tls=false

      # now specify routing for https
      - traefik.http.routers.whoami.entrypoints=websecure
      - traefik.http.routers.whoami.rule=Host("whoami1.programster.org")
      - traefik.http.routers.whoami.tls=true

Redirecting HTTP to HTTPS

If you would like to redirect HTTP connections to HTTPS on a per-service basis (e.g. not configure Traefik to do this globally for all connections), then one can just update the service's labels to add a middleware to perform this routing on the HTTP endpoint.

version: "3.9"

networks:
  traefik-net:
    external: true

services:
  whoami:
    container_name: whoami
    image: traefik/whoami
    networks: 
      - traefik-net
    labels:
      # Specify http routing
      - traefik.http.routers.whoamihttp.entrypoints=web
      - traefik.http.routers.whoamihttp.rule=Host("whoami1.programster.org")
      - traefik.http.routers.whoamihttp.tls=false
      # Add middleware to redirect http to https on port 443
      - traefik.http.middlewares.redirect-web-secure.redirectscheme.scheme=https
      - traefik.http.routers.whoamihttp.middlewares=redirect-web-secure

      # now specify routing for https
      - traefik.http.routers.whoami.entrypoints=websecure
      - traefik.http.routers.whoami.rule=Host("whoami1.programster.org")
      - traefik.http.routers.whoami.tls=true

It is the two lines under # Add middleware to redirect http to https on port 443 that are relevant to this section. On the first like, we create a middleware called redirect-web-secure, which is set to change the scheme to https. On the second line, we register the middleware against the whoamihttp router, (which listens on the web entrypoint).

Exposed By Default

In the configurations above, I had exposedByDefault set to true in the static configuration file, like so:

# ...
providers:
  docker:
    endpoint: unix:///var/run/docker.sock
    exposedByDefault: true
  file:
    directory: /etc/traefik/dynamic

This will mean that all containers run on the host will be exposed by Traefik, by default, meaning that it will create routes for all detected containers. You may (likely) not wish for this to be the case. Thus I would recommend setting this to false like so:

# ...
providers:
  docker:
    endpoint: unix:///var/run/docker.sock
    exposedByDefault: false
  file:
    directory: /etc/traefik/dynamic

... but now for all the services that you do wish to be exposed through Traefik, you need to add the traefik.enable=true label them, to tell Traefik to go ahead and let them be exposed. This can be done in the docker-compose configuration like so:

services:
  app:
    labels:
      - traefik.enable=true

References

Last updated: 22nd June 2023
First published: 2nd September 2022

This blog is created by Stuart Page

I'm a freelance web developer and technology consultant based in Surrey, UK, with over 10 years experience in web development, DevOps, Linux Administration, and IT solutions.

Need support with your infrastructure or web services?

Get in touch