<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: karvounis</title>
    <description>The latest articles on DEV Community by karvounis (@karvounis).</description>
    <link>https://dev.to/karvounis</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F352655%2F9aaa559a-41ef-42a0-a4a9-9ffbb88f5814.jpeg</url>
      <title>DEV Community: karvounis</title>
      <link>https://dev.to/karvounis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/karvounis"/>
    <language>en</language>
    <item>
      <title>Introducing a Terraform provider for Forem</title>
      <dc:creator>karvounis</dc:creator>
      <pubDate>Thu, 14 Apr 2022 06:44:36 +0000</pubDate>
      <link>https://dev.to/karvounis/introducing-a-terraform-provider-for-forem-3o2h</link>
      <guid>https://dev.to/karvounis/introducing-a-terraform-provider-for-forem-3o2h</guid>
      <description>&lt;p&gt;I am glad to announce that I have just released a Terraform provider for Forem! This provider is my small contibution to this amazing open-source project. You can find its source code on &lt;a href="https://github.com/karvounis/terraform-provider-forem"&gt;Github&lt;/a&gt; and the provider's page on &lt;a href="https://registry.terraform.io/providers/karvounis/forem/latest"&gt;Terraform registry&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Manage your Forem resources using code! Forem as Code (FaC) following the &lt;a href="https://www.ibm.com/cloud/learn/infrastructure-as-code"&gt;Infrastructure as Code&lt;/a&gt; (IaC) concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Need
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/forem/forem"&gt;Forem&lt;/a&gt; is a great software project and the platform that powers &lt;a href="https://dev.to/"&gt;dev.to&lt;/a&gt;. When I published my first article in &lt;code&gt;dev.to&lt;/code&gt;, I found it very easy to navigate through the browser interface of Forem, create, write, and edit the article.&lt;/p&gt;

&lt;p&gt;However, while I was writing the second article, I realised that there are a lot of similarities between them and that certain things can be automated. I also realised that the more articles you publish, the harder their maintenance is going to get. Using just the browser does not scale well and there is certainly room for automation.&lt;/p&gt;

&lt;p&gt;I decided to use &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt; to automate the management of Forem resources. Quoted from their website:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Terraform is an open-source infrastructure as code software tool that provides a consistent CLI workflow to manage hundreds of cloud services. Terraform codifies cloud APIs into declarative configuration files.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If there is an API, you can create a Terraform provider for it!&lt;/p&gt;

&lt;h2&gt;
  
  
  API
&lt;/h2&gt;

&lt;p&gt;Forem has an &lt;a href="https://developers.forem.com/api"&gt;API&lt;/a&gt; that you can use in order to create and update articles, listings and a few other resources. Instead of using the browser, you can send HTTP requests to the &lt;code&gt;api&lt;/code&gt; endpoint of the Forem installation and read, create or update the resources you need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;You can either visit the linkg &lt;a href="https://dev.to/karvounis/basic-traefik-configuration-tutorial-593m"&gt;https://dev.to/karvounis/basic-traefik-configuration-tutorial-593m&lt;/a&gt; from your browser or send the following &lt;code&gt;curl&lt;/code&gt; request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://dev.to/api/articles/karvounis/basic-traefik-configuration-tutorial-593m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to use it
&lt;/h2&gt;

&lt;p&gt;The provider requires two arguments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;api_key&lt;/code&gt; (String) API key to be able to communicate with the FOREM API. Can be specified with the &lt;code&gt;FOREM_API_KEY&lt;/code&gt; environment variable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;host&lt;/code&gt; (String) Host of the FOREM API. You can specify the &lt;code&gt;dev.to&lt;/code&gt; or any other Forem installation. Can be specified with the &lt;code&gt;FOREM_HOST&lt;/code&gt; environment variable. Default: &lt;code&gt;https://dev.to/api&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to generate an API key, go to &lt;code&gt;Settings -&amp;gt; Account -&amp;gt; DEV Community API Keys&lt;/code&gt;, give it a proper description and press the &lt;code&gt;Generate API Key&lt;/code&gt; button.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forem Articles through Terraform
&lt;/h3&gt;

&lt;p&gt;You can create a new Forem article using the examples shown &lt;a href="https://registry.terraform.io/providers/karvounis/forem/latest/docs/resources/article#example-usage"&gt;here&lt;/a&gt;. In this example, both &lt;code&gt;example_file&lt;/code&gt; and &lt;code&gt;example_full&lt;/code&gt; articles use the same tags that are defined in the &lt;code&gt;locals&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;Imagine having way more articles maintained by Terraform and you need to remove a specific tag from all of them. With this provider, you can just remove that tag from the list, re-run the plan and Terraform will be smart enough to understand the difference and remove this tag from all the articles. By doing that, we saved ourselves a lot of clicks!&lt;/p&gt;

&lt;h2&gt;
  
  
  Currently supported
&lt;/h2&gt;

&lt;p&gt;Currently, the lastest Terraform provider version is &lt;code&gt;1.0.1&lt;/code&gt; and supports the following Forem resources and actions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resources&lt;/th&gt;
&lt;th&gt;Actions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Articles&lt;/td&gt;
&lt;td&gt;Create, Update, Read, Import&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Listings&lt;/td&gt;
&lt;td&gt;Create, Update, Read, Import&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data Sources&lt;/th&gt;
&lt;th&gt;Actions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Articles&lt;/td&gt;
&lt;td&gt;Get By ID, Get By username and slug&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Listings&lt;/td&gt;
&lt;td&gt;Get By ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Users&lt;/td&gt;
&lt;td&gt;Get By ID, Get By username&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I really hope that this provider is going to help all people using &lt;strong&gt;Forem&lt;/strong&gt;. In fact, this very article has been generated using this provider! Don’t take my word for it, check the Terraform &lt;a href="https://github.com/karvounis/forem-resources/blob/master/articles_forem.tf#L1-L7"&gt;article resource&lt;/a&gt; and the actual &lt;a href="https://github.com/karvounis/forem-resources/blob/master/files/forem/terraform_provider_intro.md"&gt;Markdown file&lt;/a&gt;! 😉&lt;/p&gt;

&lt;p&gt;Any contributions to the provider are welcome and I would appreciate any feedback in the comments section! Cheers!&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/karvounis/terraform-provider-forem"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/karvounis/terraform-provider-forem/projects/1"&gt;Project Roadmap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/karvounis/dev-client-go"&gt;Go Forem client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://registry.terraform.io/providers/karvounis/forem/latest"&gt;Terraform registry&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>announcement</category>
      <category>forem</category>
      <category>automation</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Advanced Traefik configuration tutorial - TLS, dashboard, ping, metrics, authentication and more</title>
      <dc:creator>karvounis</dc:creator>
      <pubDate>Thu, 24 Mar 2022 18:46:20 +0000</pubDate>
      <link>https://dev.to/karvounis/advanced-traefik-configuration-tutorial-tls-dashboard-ping-metrics-authentication-and-more-4doh</link>
      <guid>https://dev.to/karvounis/advanced-traefik-configuration-tutorial-tls-dashboard-ping-metrics-authentication-and-more-4doh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This tutorial is the second part of the Traefik series. The first part can be found &lt;a href="https://dev.to/karvounis/basic-traefik-configuration-tutorial-593m"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the previous tutorial, the basic Traefik concepts were explained and we showed a simple Traefik configuration running in standalone Docker. In this tutorial, we are going to cover some advanced concepts such as TLS, authentication and chain middlewares, the Traefik dashboard, Traefik metrics for Prometheus, and healthchecks.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The codebase for this tutorial can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/tree/master/standalone/advanced" rel="noopener noreferrer"&gt;here&lt;/a&gt;. All docker-compose files that appear in the Traefik tutorials can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Docker compose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All docker compose files have been tested with Docker 20.10.12 and docker-compose 1.24.0.&lt;/p&gt;

&lt;p&gt;Create the required Docker networks&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker network create traefik_public
docker network create socket_proxy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fkarvounis%2Ftraefik-tutorial-docker-compose-files%2Fblob%2Fmaster%2Fstandalone%2Fadvanced%2Fimages%2Ftldr-doge.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fkarvounis%2Ftraefik-tutorial-docker-compose-files%2Fblob%2Fmaster%2Fstandalone%2Fadvanced%2Fimages%2Ftldr-doge.jpg%3Fraw%3Dtrue" title="TLDR Doge" alt="tldr-doge"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Advanced concepts
&lt;/h2&gt;
&lt;h3&gt;
  
  
  TLS
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The full &lt;code&gt;docker-compose&lt;/code&gt; file for this section can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/blob/master/standalone/advanced/docker-compose.tls.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Traefik can be configured to accept incoming &lt;a href="https://doc.traefik.io/traefik/https/overview/" rel="noopener noreferrer"&gt;HTTPS connections&lt;/a&gt; in order to terminate the SSL connections (meaning that it will send decrypted data to the services). It can be configured to use an &lt;a href="https://doc.traefik.io/traefik/https/acme/" rel="noopener noreferrer"&gt;ACME provider&lt;/a&gt; (like Let's Encrypt) for automatic certificate generation. However, we are not going to cover this as there is already a plethora of very informative material on the subject online. In this tutorial, we are going to create our own CA and Traefik certificates and configure Traefik to use them.&lt;/p&gt;
&lt;h4&gt;
  
  
  Certificates
&lt;/h4&gt;

&lt;p&gt;We need to create our own TLS certificates in order to have encryption in transit and properly secure the communication from and to Traefik. I have already generated some certificates which can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/tree/master/standalone/advanced/certs" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, you can create your own certificates by running the following commands:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; certs/&lt;span class="o"&gt;{&lt;/span&gt;ca,traefik&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# Create CA certificates&lt;/span&gt;
openssl genrsa &lt;span class="nt"&gt;-out&lt;/span&gt; certs/ca/rootCA.key 4096
openssl req &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-days&lt;/span&gt; 3650 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-key&lt;/span&gt; certs/ca/rootCA.key &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/C=GR/L=Athens/O=Karvounis Tutorials, Inc./CN=Karvounis Root CA/OU=CA department"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-out&lt;/span&gt; certs/ca/rootCA.pem
&lt;span class="c"&gt;# Create Traefik wildcard certificates&lt;/span&gt;
openssl genrsa &lt;span class="nt"&gt;-out&lt;/span&gt; certs/traefik/traefik.key 4096
openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-key&lt;/span&gt; certs/traefik/traefik.key &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/C=GR/L=Athens/O=Karvounis Tutorials, Inc./CN=*.karvounis.tutorial/OU=Dev.to"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-out&lt;/span&gt; certs/traefik/traefik.csr
openssl x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-days&lt;/span&gt; 365 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-CA&lt;/span&gt; certs/ca/rootCA.pem &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-CAkey&lt;/span&gt; certs/ca/rootCA.key &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-CAcreateserial&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-in&lt;/span&gt; certs/traefik/traefik.csr &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-out&lt;/span&gt; certs/traefik/traefik.crt


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above commands will create the necessary certificates under the following directory structure:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;tree certs/
certs/
├── ca
│   ├── rootCA.key
│   ├── rootCA.pem
│   └── rootCA.srl
└── traefik
    ├── traefik.crt
    ├── traefik.csr
    └── traefik.key


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The generated traefik certificate is a wildcard certificate for &lt;code&gt;*.karvounis.tutorial&lt;/code&gt; and will cover all the use cases for the tutorials. From now on, we are going to use these certificates in every &lt;code&gt;docker-compose&lt;/code&gt; file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Service configuration
&lt;/h4&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik:v2.6&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Entrypoints configuration&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--entrypoints.web.address=:80&lt;/span&gt;
    &lt;span class="c1"&gt;## Create a new entrypoint called `websecure` that is going to be used for TLS&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--entrypoints.websecure.address=:443&lt;/span&gt;
    &lt;span class="c1"&gt;## Forces redirection of incoming requests from `web` to `websecure` entrypoint&lt;/span&gt;
    &lt;span class="c1"&gt;## https://doc.traefik.io/traefik/routing/entrypoints/#redirection&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--entrypoints.web.http.redirections.entryPoint.to=websecure&lt;/span&gt;
    &lt;span class="c1"&gt;# Docker provider configuration&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.exposedbydefault=false&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.endpoint=tcp://socket_proxy:2375&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.network=traefik_public&lt;/span&gt;
    &lt;span class="c1"&gt;# File provider configuration&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.file.directory=/traefik/config/my_dynamic_conf&lt;/span&gt;
    &lt;span class="c1"&gt;# Logging configuration&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--log.level=info&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--log.format=json&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;80:80&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;443:443&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./certs/traefik:/traefik/config/certs:ro&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config.yml:/traefik/config/my_dynamic_conf/conf.yml:ro&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik_public&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;socket_proxy&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;socket_proxy&lt;/span&gt;

&lt;span class="na"&gt;whoami&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik/whoami:v1.7.1&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.entrypoints=websecure&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.rule=Host(`whoami.karvounis.tutorial`)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.service=whoami_service&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.tls=true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.services.whoami_service.loadbalancer.server.port=80&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik_public&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  Entrypoints configuration
&lt;/h5&gt;
&lt;h6&gt;
  
  
  --entrypoints.websecure.address=:443
&lt;/h6&gt;

&lt;p&gt;Defines an entrypoint called &lt;code&gt;websecure&lt;/code&gt; that will listen on port 443 of the Traefik container. This entrypoint is going to be used for all the TLS connections.&lt;/p&gt;
&lt;h6&gt;
  
  
  --entrypoints.web.http.redirections.entryPoint.to=websecure
&lt;/h6&gt;

&lt;p&gt;It enables permanent redirecting of all incoming requests from the &lt;code&gt;web&lt;/code&gt; entrypoint to the &lt;code&gt;websecure&lt;/code&gt; entrypoint. That means that even if someone tries to send an HTTP request, that request will be redirected to HTTPS.&lt;/p&gt;
&lt;h5&gt;
  
  
  File provider configuration
&lt;/h5&gt;

&lt;p&gt;TLS certification configuration is part of the dynamic configuration of Traefik. Unfortunately, we cannot use the &lt;a href="https://doc.traefik.io/traefik/reference/dynamic-configuration/docker/" rel="noopener noreferrer"&gt;Docker provider&lt;/a&gt; in order to dynamically configure tls certificates using labels. We have to use the &lt;a href="https://doc.traefik.io/traefik/reference/dynamic-configuration/file/" rel="noopener noreferrer"&gt;File provider&lt;/a&gt; instead.&lt;/p&gt;
&lt;h6&gt;
  
  
  --providers.file.directory=/traefik/config/my_dynamic_conf
&lt;/h6&gt;

&lt;p&gt;Points to the directory where Traefik can load the dynamic configuration from. In our case, we are going to mount a &lt;code&gt;config.yml&lt;/code&gt; file that contains the paths to our certificates.&lt;/p&gt;
&lt;h5&gt;
  
  
  Volumes
&lt;/h5&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./certs/traefik:/traefik/config/certs:ro&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./config.yml:/traefik/config/my_dynamic_conf/conf.yml:ro&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Mounts the local &lt;code&gt;./certs/traefik&lt;/code&gt; folder and its contents (the Traefik certificates) to the &lt;code&gt;/traefik/config/certs&lt;/code&gt; inside the container. Local &lt;code&gt;./config.yml&lt;/code&gt; file, that contains the dynamic configuration, will be mounted inside the &lt;code&gt;/traefik/config/my_dynamic_conf/&lt;/code&gt; directory, which is the directory that Traefik looks for its dynamic configuration from.&lt;/p&gt;

&lt;p&gt;The path of Traefik's public key and private key in the container are &lt;code&gt;/traefik/config/certs/traefik.crt&lt;/code&gt; and &lt;code&gt;/traefik/config/certs/traefik.key&lt;/code&gt; respectively.&lt;/p&gt;

&lt;h5&gt;
  
  
  Config
&lt;/h5&gt;

&lt;p&gt;The following config file, which can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/blob/master/standalone/advanced/config.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;, is used to define the paths in the container for the certificate and the key.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;certificates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;certFile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/traefik/config/certs/traefik.crt&lt;/span&gt;
      &lt;span class="na"&gt;keyFile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/traefik/config/certs/traefik.key&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  whoami service labels
&lt;/h5&gt;

&lt;p&gt;We are going to enable TLS for the &lt;code&gt;whoami_route&lt;/code&gt;. This can be achieved by changing the value of the &lt;code&gt;traefik.http.routers.whoami_route.entrypoints&lt;/code&gt; to &lt;code&gt;websecure&lt;/code&gt; (the HTTPS entrypoint) and setting the &lt;code&gt;traefik.http.routers.whoami_route.tls&lt;/code&gt; label to true.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.entrypoints=websecure&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.rule=Host(`whoami.karvounis.tutorial`)&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.service=whoami_service&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.tls=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.services.whoami_service.loadbalancer.server.port=80&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Deployment
&lt;/h4&gt;

&lt;p&gt;Deploy the containers by executing the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.tls.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  Requests
&lt;/h5&gt;

&lt;p&gt;First, we are going to send a request to &lt;code&gt;http://whoami.karvounis.tutorial&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Host: whoami.karvounis.tutorial"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    http://localhost
&lt;span class="c"&gt;# OR curl http://whoami.karvounis.tutorial&lt;/span&gt;
Moved Permanently


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The response is &lt;strong&gt;Moved Permanently&lt;/strong&gt; due to the redirection that we configured with this command: &lt;code&gt;--entrypoints.web.http.redirections.entryPoint.to=websecure&lt;/code&gt;. Every request to the HTTP &lt;code&gt;web&lt;/code&gt; entrypoint will be automatically redirected to the HTTPS &lt;code&gt;websecure&lt;/code&gt; entrypoint!&lt;/p&gt;

&lt;p&gt;Let's try to directly hit the HTTPS entrypoint:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;--cacert&lt;/span&gt; ./certs/ca/rootCA.pem &lt;span class="se"&gt;\&lt;/span&gt;
    https://whoami.karvounis.tutorial
Hostname: 5f1a8f92cd2b
IP: 127.0.0.1
IP: 172.19.0.2
RemoteAddr: 172.19.0.3:53910
GET / HTTP/1.1
Host: whoami.karvounis.tutorial
User-Agent: curl/7.68.0
Accept: &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;
Accept-Encoding: &lt;span class="nb"&gt;gzip
&lt;/span&gt;X-Forwarded-For: 172.20.0.1
X-Forwarded-Host: whoami.karvounis.tutorial
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Server: 40e915108da5
X-Real-Ip: 172.20.0.1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Success! Sending a request to the HTTPS entrypoint and specifying the public key of the CA, returned the expected response.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ping
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The full &lt;code&gt;docker-compose&lt;/code&gt; file for this section can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/blob/master/standalone/advanced/docker-compose.ping.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Traefik provides a &lt;code&gt;ping&lt;/code&gt; &lt;a href="https://doc.traefik.io/traefik/operations/ping/" rel="noopener noreferrer"&gt;endpoint&lt;/a&gt; that, when enabled, can be used to check the health of the Traefik instance.&lt;/p&gt;

&lt;h4&gt;
  
  
  Configuration changes
&lt;/h4&gt;

&lt;h5&gt;
  
  
  --ping=true
&lt;/h5&gt;

&lt;p&gt;Enables the &lt;code&gt;/ping&lt;/code&gt; healthcheck URL. However, we are not going to expose it using a router. Instead, we are going to use the URL to check the health of the Docker container by leveraging docker-compose's &lt;a href="https://docs.docker.com/compose/compose-file/compose-file-v3/#healthcheck" rel="noopener noreferrer"&gt;healthcheck&lt;/a&gt; option.&lt;/p&gt;

&lt;h5&gt;
  
  
  healthcheck configuration
&lt;/h5&gt;

&lt;p&gt;Every 10 seconds, Docker is going to execute the command &lt;code&gt;traefik healthcheck --ping&lt;/code&gt; to establish the health of each Traefik instance (&lt;a href="https://doc.traefik.io/traefik/operations/cli/#healthcheck" rel="noopener noreferrer"&gt;docs&lt;/a&gt;). If the command is unsuccessful for 3 consecutive times, Docker will mark the container as unhealthy and will restart it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Run traefik healthcheck command&lt;/span&gt;
    &lt;span class="c1"&gt;# https://doc.traefik.io/traefik/operations/cli/#healthcheck&lt;/span&gt;
    &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;healthcheck"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--ping"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10s&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
    &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;start_period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Deployment
&lt;/h4&gt;

&lt;p&gt;Deploy the containers by executing the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.ping.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Check the status of the traefik service by executing:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.ping.yml ps traefik


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After a few seconds, traefik service's status will change from &lt;code&gt;starting&lt;/code&gt; to &lt;code&gt;healthy&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dashboard
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The full &lt;code&gt;docker-compose&lt;/code&gt; file for this section can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/blob/master/standalone/advanced/docker-compose.dashboard.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Traefik offers a &lt;a href="https://doc.traefik.io/traefik/operations/dashboard/" rel="noopener noreferrer"&gt;dashboard&lt;/a&gt; where you can view all the active routers, services and middlewares. In this section, we are going to find out how to enable the dashboard and how to configure the routers to be able to access it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Traefik service configuration
&lt;/h4&gt;

&lt;p&gt;This is the first time we are going to add Docker labels to the &lt;code&gt;traefik&lt;/code&gt; service. They are going to define a new router, called &lt;code&gt;dashboard&lt;/code&gt;, which will only be accessible through TLS.&lt;/p&gt;

&lt;p&gt;In order to enable the &lt;code&gt;dashboard&lt;/code&gt; and the &lt;code&gt;api&lt;/code&gt;, you have to add the &lt;code&gt;--api.dashboard=true&lt;/code&gt; to the &lt;code&gt;command&lt;/code&gt; configuration option of the &lt;code&gt;traefik&lt;/code&gt; service.&lt;/p&gt;

&lt;h5&gt;
  
  
  Service labels
&lt;/h5&gt;

&lt;p&gt;The Docker labels below define a new router called &lt;code&gt;dashboard&lt;/code&gt;. This router uses a &lt;strong&gt;Host Based rule&lt;/strong&gt; as well as two &lt;strong&gt;PathPrefix&lt;/strong&gt; rules to be able to match all the necessary requests. This router is only accessible through the &lt;code&gt;websecure&lt;/code&gt; entrypoint.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.dashboard.rule=Host(`traefik.karvounis.tutorial`) &amp;amp;&amp;amp; (PathPrefix(`/api`) || PathPrefix(`/dashboard`))&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.dashboard.tls=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.dashboard.entrypoints=websecure&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.dashboard.service=api@internal&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Deployment
&lt;/h4&gt;

&lt;p&gt;Deploy the containers by executing the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.dashboard.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  UI
&lt;/h5&gt;

&lt;p&gt;You can access the dashboard by visiting &lt;code&gt;https://traefik.karvounis.tutorial/dashboard/&lt;/code&gt; and the &lt;code&gt;api&lt;/code&gt; at &lt;code&gt;https://traefik.karvounis.tutorial/api/rawdata&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tip: Do not forget the trailing slash &lt;code&gt;/&lt;/code&gt; in &lt;code&gt;/dashboard/&lt;/code&gt;!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fkarvounis%2Ftraefik-tutorial-docker-compose-files%2Fblob%2Fmaster%2Fstandalone%2Fadvanced%2Fimages%2Ftraefik_dashboard.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fkarvounis%2Ftraefik-tutorial-docker-compose-files%2Fblob%2Fmaster%2Fstandalone%2Fadvanced%2Fimages%2Ftraefik_dashboard.jpg%3Fraw%3Dtrue" title="Traefik Dashboard" alt="traefik-dashboard"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The full &lt;code&gt;docker-compose&lt;/code&gt; file for this section can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/blob/master/standalone/advanced/docker-compose.auth.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After exposing the dashboard in the previous section, it is clear that we need to secure it and restrict access only to authenticated users.&lt;br&gt;
Traefik offers the following HTTP Authentication middlewares:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://doc.traefik.io/traefik/middlewares/http/basicauth/" rel="noopener noreferrer"&gt;BasicAuth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://doc.traefik.io/traefik/middlewares/http/digestauth/" rel="noopener noreferrer"&gt;DigestAuth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://doc.traefik.io/traefik/middlewares/http/forwardauth/" rel="noopener noreferrer"&gt;ForwardAuth&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this section, we are going to use the &lt;code&gt;BasicAuth&lt;/code&gt; middleware to secure the &lt;code&gt;dashboard&lt;/code&gt; router and the &lt;code&gt;DigestAuth&lt;/code&gt; to secure the &lt;code&gt;whoami&lt;/code&gt; router.&lt;/p&gt;
&lt;h4&gt;
  
  
  Configuration changes
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;traefik&lt;/code&gt; service:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.dashboard.rule=Host(`traefik.karvounis.tutorial`) &amp;amp;&amp;amp; (PathPrefix(`/api`) || PathPrefix(`/dashboard`))&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.dashboard.tls=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.dashboard.entrypoints=websecure&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.dashboard.service=api@internal&lt;/span&gt;
    &lt;span class="c1"&gt;# Middlewares&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.dashboard.middlewares=dashboard_auth&lt;/span&gt;
    &lt;span class="c1"&gt;## Creates 2 authentication middlewares&lt;/span&gt;
    &lt;span class="c1"&gt;### `dashboard_auth` is a BasicAuth middleware and is going to be used by the `dashboard` router.&lt;/span&gt;
    &lt;span class="c1"&gt;### dashboard:tutorial&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.middlewares.dashboard_auth.basicauth.users=dashboard:$$2y$$05$$T/WVjQVqBc24NLUNI/xuVu0V2B.RPY50k2.CCH5JHGInb3EUeaDcO&lt;/span&gt;
    &lt;span class="c1"&gt;### `auth` is a DigestAuth middleware and is going to be used by the `whoami_route` router.&lt;/span&gt;
    &lt;span class="c1"&gt;### whoami:tutorial&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.middlewares.digest_auth.digestauth.users=whoami:traefik:f4ba293a96d5dcf51eb2f03b5931dd96&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;whoami&lt;/code&gt; service:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.entrypoints=websecure&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.rule=Host(`whoami.karvounis.tutorial`)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.service=whoami_service&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.tls=true&lt;/span&gt;
      &lt;span class="c1"&gt;# `whoami_route` uses the `digest_auth` middleware defined in the `traefik` service&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.middlewares=digest_auth&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.services.whoami_service.loadbalancer.server.port=80&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  traefik.http.middlewares.dashboard_auth.basicauth.users
&lt;/h5&gt;

&lt;p&gt;This label creates a new &lt;code&gt;BasicAuth&lt;/code&gt; middleware called &lt;code&gt;dashboard_auth&lt;/code&gt;. It contains the user with the credentials &lt;code&gt;dashboard:tutorial&lt;/code&gt; and can contain an array of authorized users. If you have a great number of users, you can also add their credentials to a file, mount that file to the container and specify the &lt;code&gt;usersFile&lt;/code&gt; option to point to that file.&lt;/p&gt;

&lt;p&gt;You can generate the passwords with the following ways:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Using the httpd:2.4-alpine image which is 58.2MB&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; httpd:2.4-alpine htpasswd &lt;span class="nt"&gt;-nbB&lt;/span&gt; dashboard tutorial | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; s/&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="nv"&gt;$\&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;/g
&lt;span class="c"&gt;# OR with `xmartlabs/htpasswd` docker image which is 9MB&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-ti&lt;/span&gt; xmartlabs/htpasswd dashboard tutorial | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; s/&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="nv"&gt;$\&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;/g
&lt;span class="c"&gt;# OR without docker&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;htpasswd &lt;span class="nt"&gt;-nbB&lt;/span&gt; dashboard tutorial | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; s/&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="nv"&gt;$\&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;/g

dashboard:&lt;span class="nv"&gt;$$&lt;/span&gt;2y&lt;span class="nv"&gt;$$&lt;/span&gt;05&lt;span class="nv"&gt;$$&lt;/span&gt;T/WVjQVqBc24NLUNI/xuVu0V2B.RPY50k2.CCH5JHGInb3EUeaDcO


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Tip: when used in &lt;code&gt;docker-compose.yml&lt;/code&gt;, all dollar signs in the hash need to be doubled for escaping!&lt;/em&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  traefik.http.middlewares.digest_auth.digestauth.users
&lt;/h5&gt;

&lt;p&gt;This label creates a new &lt;code&gt;DigestAuth&lt;/code&gt; middleware called &lt;code&gt;digest_auth&lt;/code&gt;. It contains the user with the credentials &lt;code&gt;whoami:tutorial&lt;/code&gt; and can contain an array of authorized users. The &lt;code&gt;usersFile&lt;/code&gt; option is available here as well.&lt;/p&gt;

&lt;p&gt;You can generate the digest credentials with the following commands:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;print &lt;span class="nb"&gt;whoami&lt;/span&gt;:traefik:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf whoami&lt;/span&gt;:traefik:tutorial | &lt;span class="nb"&gt;md5sum&lt;/span&gt; | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $1}'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# OR with htdigest `htdigest [-c] passwordfile realm username` and type the password&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;htdigest &lt;span class="nt"&gt;-c&lt;/span&gt; /tmp/pwd_file traefik &lt;span class="nb"&gt;whoami&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; /tmp/pwd_file

&lt;span class="nb"&gt;whoami&lt;/span&gt;:traefik:f4ba293a96d5dcf51eb2f03b5931dd96


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  traefik.http.routers.dashboard.middlewares=dashboard_auth
&lt;/h5&gt;

&lt;p&gt;Instructs the &lt;code&gt;dashboard&lt;/code&gt; router to use the &lt;code&gt;dashboard_auth&lt;/code&gt; as authentication middleware.&lt;/p&gt;
&lt;h5&gt;
  
  
  traefik.http.routers.whoami_route.middlewares=digest_auth
&lt;/h5&gt;

&lt;p&gt;Instructs the &lt;code&gt;whoami_route&lt;/code&gt; router to use the &lt;code&gt;digest_auth&lt;/code&gt; as authentication middleware.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tip: You can use middlewares defined in other services!&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Deployment
&lt;/h4&gt;

&lt;p&gt;Deploy the containers by executing the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.auth.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  Requests
&lt;/h5&gt;

&lt;p&gt;If you try to access the &lt;code&gt;https://traefik.karvounis.tutorial/api/rawdata&lt;/code&gt; URL like before, you are going to get a &lt;code&gt;401&lt;/code&gt; response status code.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;--cacert&lt;/span&gt; ./certs/ca/rootCA.pem &lt;span class="se"&gt;\&lt;/span&gt;
    https://traefik.karvounis.tutorial/api/rawdata
401 Unauthorized


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In order to access the Traefik &lt;code&gt;api&lt;/code&gt; using &lt;code&gt;curl&lt;/code&gt;, you have to specify the basic auth user credentials.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;--cacert&lt;/span&gt; ./certs/ca/rootCA.pem &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-u&lt;/span&gt; dashboard:tutorial &lt;span class="se"&gt;\&lt;/span&gt;
    https://traefik.karvounis.tutorial/api/version
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Version"&lt;/span&gt;:&lt;span class="s2"&gt;"2.6.0"&lt;/span&gt;,&lt;span class="s2"&gt;"Codename"&lt;/span&gt;:&lt;span class="s2"&gt;"rocamadour"&lt;/span&gt;,&lt;span class="s2"&gt;"startDate"&lt;/span&gt;:&lt;span class="s2"&gt;"2022-02-23T17:42:57.897252485Z"&lt;/span&gt;,&lt;span class="s2"&gt;"pilotEnabled"&lt;/span&gt;:true&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you want to access the &lt;code&gt;whoami&lt;/code&gt; service, you need to specify the digest credentials of the &lt;code&gt;whoami&lt;/code&gt; authorized user. Otherwise, Traefik is going to respond with a &lt;code&gt;401&lt;/code&gt; as above.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;--cacert&lt;/span&gt; ./certs/ca/rootCA.pem &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--digest&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nb"&gt;whoami&lt;/span&gt;:tutorial &lt;span class="se"&gt;\&lt;/span&gt;
    https://whoami.karvounis.tutorial
Hostname: 637aadaf37b3
IP: 127.0.0.1
IP: 172.19.0.2
RemoteAddr: 172.19.0.3:40984
GET / HTTP/1.1
Host: whoami.karvounis.tutorial
User-Agent: curl/7.68.0
Accept: &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;
Accept-Encoding: &lt;span class="nb"&gt;gzip
&lt;/span&gt;Authorization: Digest &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"whoami"&lt;/span&gt;, &lt;span class="nv"&gt;realm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"traefik"&lt;/span&gt;, &lt;span class="nv"&gt;nonce&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2ZZJLL5tPk8bEDU8"&lt;/span&gt;, &lt;span class="nv"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;, &lt;span class="nv"&gt;cnonce&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YzUxNzMyZWIyODNjN2VlNDIyMDkyMmY3Nzc3YjVkNDE="&lt;/span&gt;, &lt;span class="nv"&gt;nc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;00000001, &lt;span class="nv"&gt;qop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;auth, &lt;span class="nv"&gt;response&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"518ade9a297beb2f5174e2368e8cf561"&lt;/span&gt;, &lt;span class="nv"&gt;opaque&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pfm5w5vBpLYhEv7A"&lt;/span&gt;, &lt;span class="nv"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"MD5"&lt;/span&gt;
X-Forwarded-For: 172.20.0.1
X-Forwarded-Host: whoami.karvounis.tutorial
X-Forwarded-Port: 443
X-Forwarded-Proto: https
X-Forwarded-Server: 5966f55786bb
X-Real-Ip: 172.20.0.1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Chain middleware
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The full &lt;code&gt;docker-compose&lt;/code&gt; file for this section can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/blob/master/standalone/advanced/docker-compose.chain.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this section, we are going to create a new &lt;a href="https://doc.traefik.io/traefik/middlewares/http/chain/" rel="noopener noreferrer"&gt;Chain middleware&lt;/a&gt; and instruct &lt;code&gt;whoami_route&lt;/code&gt; to use it. This middleware consists of two middlewares:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A new HTTP &lt;a href="https://doc.traefik.io/traefik/middlewares/http/ratelimit/" rel="noopener noreferrer"&gt;RateLimit&lt;/a&gt; middleware called &lt;code&gt;simple_ratelimit&lt;/code&gt;. This middleware is going to limit the maximum amount of allowed requests to the &lt;code&gt;whoami_service&lt;/code&gt; service in a particular time period.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;digest_auth&lt;/code&gt; which we have already seen in the Authentication section.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;chain&lt;/code&gt; middleware is first going to pass the request through the &lt;code&gt;simple_ratelimit&lt;/code&gt; and then through the &lt;code&gt;digest_auth&lt;/code&gt; middleware. If the request manages to successfully pass both, then it will reach the &lt;code&gt;whoami_service&lt;/code&gt;. Traefik's documentation does not specify a hard limit for the amount of middlewares that you can chain.&lt;/p&gt;
&lt;h4&gt;
  
  
  Configuration changes
&lt;/h4&gt;

&lt;p&gt;We are going to create the new &lt;code&gt;simple_ratelimit&lt;/code&gt; and &lt;code&gt;secured_chain&lt;/code&gt; middlewares by adding the following labels to the &lt;code&gt;traefik&lt;/code&gt; service:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.middlewares.secured_chain.chain.middlewares=simple_ratelimit,digest_auth&lt;/span&gt;
    &lt;span class="c1"&gt;## The `simple_ratelimit` middleware allows&lt;/span&gt;
    &lt;span class="c1"&gt;## an average of 5 requests per 5 seconds&lt;/span&gt;
    &lt;span class="c1"&gt;## and a burst of 2 requests.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.middlewares.simple_ratelimit.ratelimit.average=5&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.middlewares.simple_ratelimit.ratelimit.period=5s&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.middlewares.simple_ratelimit.ratelimit.burst=2&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Based on the above numbers, the maximum allowed request rate is &lt;code&gt;r=average/period=5/5s=1 request/second&lt;/code&gt;. If we exceed that rate, the requests are going to be automatically rejected with a &lt;strong&gt;429&lt;/strong&gt; HTTP status code.&lt;/p&gt;

&lt;p&gt;We also need to instruct &lt;code&gt;whoami_route&lt;/code&gt; to use the &lt;code&gt;secured_chain&lt;/code&gt; middleware:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Use the `secured_chain` chain middleware&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.middlewares=secured_chain&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Deployment
&lt;/h4&gt;

&lt;p&gt;Deploy the containers by executing the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.chain.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  Requests
&lt;/h5&gt;

&lt;p&gt;Sending a simple &lt;code&gt;curl&lt;/code&gt; request to &lt;code&gt;https://whoami.karvounis.tutorial&lt;/code&gt; will work as before. Nothing out of the ordinary yet.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl &lt;span class="nt"&gt;--cacert&lt;/span&gt; ./certs/ca/rootCA.pem &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--digest&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nb"&gt;whoami&lt;/span&gt;:tutorial &lt;span class="se"&gt;\&lt;/span&gt;
    https://whoami.karvounis.tutorial


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The following command is going to send a curl request to &lt;code&gt;https://whoami.karvounis.tutorial&lt;/code&gt; every 1.5 seconds. All 5 requests are going to succeed because the rate is slower than the maximum allowed request rate.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;SLEEP_TIMER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.5s
&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;1..5&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Request number: &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    curl &lt;span class="nt"&gt;--cacert&lt;/span&gt; ./certs/ca/rootCA.pem &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--digest&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nb"&gt;whoami&lt;/span&gt;:tutorial &lt;span class="se"&gt;\&lt;/span&gt;
        https://whoami.karvounis.tutorial
    &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SLEEP_TIMER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;On the other hand, the following command is going to send a curl request to &lt;code&gt;https://whoami.karvounis.tutorial&lt;/code&gt; every 0.5 seconds. This request rate of 2 requests/sec is faster that the maximum allowed rate! The very first request will succeed but all the subsequent ones will be rejected with a &lt;code&gt;429 Too Many Requests&lt;/code&gt; HTTP status code.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;SLEEP_TIMER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.5s
&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;1..5&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Request number: &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    curl &lt;span class="nt"&gt;--cacert&lt;/span&gt; ./certs/ca/rootCA.pem &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--digest&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="nb"&gt;whoami&lt;/span&gt;:tutorial &lt;span class="se"&gt;\&lt;/span&gt;
        https://whoami.karvounis.tutorial
    &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SLEEP_TIMER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Metrics
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;The full &lt;code&gt;docker-compose&lt;/code&gt; file for this section can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/blob/master/standalone/advanced/docker-compose.metrics.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Currently, Traefik supports 4 &lt;a href="https://doc.traefik.io/traefik/observability/metrics/overview/" rel="noopener noreferrer"&gt;metrics backends&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Datadog&lt;/li&gt;
&lt;li&gt;InfluxDB&lt;/li&gt;
&lt;li&gt;Prometheus&lt;/li&gt;
&lt;li&gt;StatsD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this section, we are going to expose Traefik's  metrics for Prometheus.&lt;/p&gt;
&lt;h4&gt;
  
  
  Configuration changes
&lt;/h4&gt;

&lt;p&gt;First, we are going to enable the prometheus backend and disable the default internal router in order to allow one to create a custom router to the &lt;code&gt;prometheus@internal&lt;/code&gt; service.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Prometheus metrics&lt;/span&gt;
    &lt;span class="c1"&gt;## Enable prometheus metrics&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--metrics.prometheus=true&lt;/span&gt;
    &lt;span class="c1"&gt;## Create a manual router instead of the default one.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--metrics.prometheus.manualrouting=true&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--metrics.prometheus.addrouterslabels=true&lt;/span&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The custom &lt;code&gt;metrics&lt;/code&gt; router exposes the metrics through &lt;code&gt;https://traefik.karvounis.tutorial/metrics&lt;/code&gt; and uses the &lt;code&gt;dashboard_auth&lt;/code&gt; BasicAuth middleware for authentication.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;&lt;br&gt;
    &lt;span class="c1"&gt;# &lt;code&gt;metrics&lt;/code&gt; router configuration&lt;/span&gt;&lt;br&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.metrics.rule=Host(&lt;code&gt;traefik.karvounis.tutorial&lt;/code&gt;) &amp;amp;&amp;amp; PathPrefix(&lt;code&gt;/metrics&lt;/code&gt;)&lt;/span&gt;&lt;br&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.metrics.tls=true&lt;/span&gt;&lt;br&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.metrics.entrypoints=websecure&lt;/span&gt;&lt;br&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.metrics.service=prometheus@internal&lt;/span&gt;&lt;br&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.metrics.middlewares=dashboard_auth&lt;/span&gt;&lt;br&gt;
    &lt;span class="s"&gt;...&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Deployment&lt;br&gt;
&lt;/h4&gt;

&lt;p&gt;Deploy the containers by executing the following command:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;p&gt;docker-compose &lt;span class="nt"&gt;-f&lt;/span&gt; docker-compose.metrics.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Requests&lt;br&gt;
&lt;/h5&gt;

&lt;p&gt;Send the following request to &lt;code&gt;https://traefik.karvounis.tutorial/metrics&lt;/code&gt;. The response contains all the Prometheus metrics for the particular Traefik instance.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;p&gt;curl &lt;span class="nt"&gt;--cacert&lt;/span&gt; ./certs/ca/rootCA.pem &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;span class="nt"&gt;-u&lt;/span&gt; dashboard:tutorial &lt;span class="se"&gt;&amp;lt;/span&amp;gt;&lt;br&gt;
    &lt;a href="https://traefik.karvounis.tutorial/metrics" rel="noopener noreferrer"&gt;https://traefik.karvounis.tutorial/metrics&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Final notes&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this advanced tutorial on Traefik. Even more interesting tutorials are on the way! Please, let me know your thoughts in the comments section below! Cheers&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can find me on &lt;a href="https://www.linkedin.com/in/karvounis/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://github.com/karvounis/" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>traefik</category>
      <category>devops</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Basic Traefik configuration tutorial</title>
      <dc:creator>karvounis</dc:creator>
      <pubDate>Sat, 12 Feb 2022 12:20:39 +0000</pubDate>
      <link>https://dev.to/karvounis/basic-traefik-configuration-tutorial-593m</link>
      <guid>https://dev.to/karvounis/basic-traefik-configuration-tutorial-593m</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This tutorial aims to introduce Traefik, explain its basic components and show a basic configuration in Docker. I ❤️ Traefik and I hope you are going to love it too! We will go through the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cover basic Traefik v2.X concepts. In this tutorial, we are going to use Traefik &lt;a href="https://github.com/traefik/traefik/releases/tag/v2.6.0" rel="noopener noreferrer"&gt;v2.6.0&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
Setup and configure Traefik using the &lt;a href="https://doc.traefik.io/traefik/providers/docker/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; provider in Standalone Engine mode.&lt;/li&gt;
&lt;li&gt;Provide a docker-compose file to achieve the above.&lt;/li&gt;
&lt;li&gt;
Deploy a simple &lt;code&gt;whoami&lt;/code&gt; service that Traefik is going to forward requests to.

&lt;ul&gt;
&lt;li&gt;
Scale whoami service to show how Traefik loadbalances the requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The codebase for this tutorial can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files/blob/master/standalone/basic/docker-compose.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;. All docker-compose files that appear in the Traefik tutorials can be found &lt;a href="https://github.com/karvounis/traefik-tutorial-docker-compose-files" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Traefik
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/traefik/traefik" rel="noopener noreferrer"&gt;Traefik&lt;/a&gt; is an open-source reverse proxy (or Edge Router) and a loadbalancer written in Go. Its greatest strength is the dynamic generation of routes to your deployed services without any manual intervention.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Traefik
&lt;/h3&gt;

&lt;p&gt;In modern architecture, a number of different services are deployed and each one of them has X amount of instances running at the same time. When you receive a request for a particular service, you must find a way to route this request to a healthy instance of this service and provide the response. What is more, the number of instances of a particular service can frequently change based on various factors such as traffic load and cpu and memory usage. You must find a way to dynamically update the routes to your services, route requests only to healthy instances and discard the unhealthy ones.&lt;/p&gt;

&lt;p&gt;Traefik solves the above problem by dynamically updating the available routes to each service and their respective instances, thus making service discovery easy. Just imagine how difficult, error-prone and irritating task would be to manually update the routes whenever a service gets created/destroyed/scaled up or down, which can happen all too often during the day.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdoc.traefik.io%2Ftraefik%2Fassets%2Fimg%2Fquickstart-diagram.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdoc.traefik.io%2Ftraefik%2Fassets%2Fimg%2Fquickstart-diagram.png" title="Simple Use Case Using Docker" alt="Docker Use case"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Docker compose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All docker compose files have been tested with Docker 20.10.12 and docker-compose 1.24.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Providers
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://doc.traefik.io/traefik/providers/overview/" rel="noopener noreferrer"&gt;Providers&lt;/a&gt; are the infrastructure components that Traefik is using for configuration discovery. Under the bonnet, Traefik queries the providers' APIs and based on the information it receives, it dynamically updates the routes.&lt;/p&gt;

&lt;p&gt;There are a number of &lt;a href="https://doc.traefik.io/traefik/providers/overview/#supported-providers" rel="noopener noreferrer"&gt;supported providers&lt;/a&gt; like Docker, ECS, Kubernetes, Consul, Rancher etc. In this tutorial, we are going to use the &lt;a href="https://doc.traefik.io/traefik/providers/docker/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; provider and use container labels for routing configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entrypoints
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://doc.traefik.io/traefik/routing/entrypoints/" rel="noopener noreferrer"&gt;Entrypoints&lt;/a&gt; listen for incoming traffic on specified ports and for a specific protocol (TCP or UDP). The most popular entrypoints are the ones that listen on ports 80 and 443. Entrypoints are part of the static configuration of Traefik, which means that you have to define them using a file (YAML or TOML) or CLI arguments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routers
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://doc.traefik.io/traefik/routing/routers/" rel="noopener noreferrer"&gt;Routers&lt;/a&gt; analyse the incoming requests and based on a set of rules make sure that the requests end up on the appropriate services. They may also use middlewares before forwarding the request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdoc.traefik.io%2Ftraefik%2Fassets%2Fimg%2Frouters.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdoc.traefik.io%2Ftraefik%2Fassets%2Fimg%2Frouters.png" title="Traefik routers" alt="Traefik routers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Middlewares
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://doc.traefik.io/traefik/middlewares/overview/" rel="noopener noreferrer"&gt;Middlewares&lt;/a&gt; can be attached to routers and can be used to analyse/enhance/change/reject the requests before they reach the services. If wanted, they can be chained together and some common use cases are authentication, redirection, path modification etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Services
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://doc.traefik.io/traefik/routing/services/" rel="noopener noreferrer"&gt;Services&lt;/a&gt; configure the way to forward the requests to your actual services. They configure things like load balancing (round-robin only as of version 2.6), health checks, sticky sessions etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup and configure Traefik
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Preparation
&lt;/h3&gt;

&lt;p&gt;Pull the necessary images&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker pull traefik:v2.6
docker pull tecnativa/docker-socket-proxy:latest
docker pull traefik/whoami:v1.7.1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Create the Docker networks that we are going to use&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker network create traefik_public
docker network create socket_proxy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;traefik_public&lt;/code&gt; is going to be used by every service that needs to be exposed by Traefik.&lt;br&gt;
&lt;code&gt;socket_proxy&lt;/code&gt; is just going to be used by &lt;code&gt;traefik&lt;/code&gt; and &lt;code&gt;socket_proxy&lt;/code&gt; services to communicate and isolated from the services that need exposure through Traefik.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration explanation
&lt;/h3&gt;

&lt;p&gt;Our setup consists of three Docker services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;traefik&lt;/strong&gt;: Listens to host port 80 and forwards the requests to any appropriate routes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;whoami&lt;/strong&gt;: Defines a router and a service using Docker labels. The goal is to serve requests to this service while sitting behing the &lt;code&gt;traefik&lt;/code&gt; reverse proxy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;socket_proxy&lt;/strong&gt;: A security-enhanced proxy for the Docker Socket. It is only going to be used by Traefik.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We are now going to explain the configuration bit by bit. &lt;em&gt;Tip: Skip to the full docker-compose file here.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Traefik service
&lt;/h4&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik:v2.6&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Entrypoints configuration&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--entrypoints.web.address=:80&lt;/span&gt;
      &lt;span class="c1"&gt;# Docker provider configuration&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker=true&lt;/span&gt;
      &lt;span class="c1"&gt;# Makes sure that services have to explicitly direct Traefik to expose them&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.exposedbydefault=false&lt;/span&gt;
      &lt;span class="c1"&gt;# Use the secure docker socket proxy&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.endpoint=tcp://socket_proxy:2375&lt;/span&gt;
      &lt;span class="c1"&gt;# Default docker network to use for connections to all containers&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.network=traefik_public&lt;/span&gt;
      &lt;span class="c1"&gt;# Logging levels are DEBUG, PANIC, FATAL, ERROR, WARN, and INFO.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--log.level=info&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;80:80&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h5&gt;
  
  
  Entrypoints configuration
&lt;/h5&gt;
&lt;h6&gt;
  
  
  --entrypoints.web.address=:80
&lt;/h6&gt;

&lt;p&gt;Defines an entrypoint called web that will listen on port 80 of the Traefik container.&lt;br&gt;
By specifying the ports using the short syntax &lt;code&gt;HOST_PORT:CONTAINER_PORT&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ports:
  - 80:80


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;you are publishing the port 80 inside the container to the host's port 80. That way, Traefik is going to receive the requests heading to &lt;code&gt;localhost:80&lt;/code&gt; or &lt;code&gt;http://localhost&lt;/code&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  Docker provider configuration
&lt;/h5&gt;

&lt;h6&gt;
  
  
  --providers.docker=true
&lt;/h6&gt;

&lt;p&gt;Enables the docker provider.&lt;/p&gt;

&lt;h6&gt;
  
  
  --providers.docker.exposedbydefault=false
&lt;/h6&gt;

&lt;p&gt;Only services that have the Docker label &lt;code&gt;traefik.enable=true&lt;/code&gt; will be discovered and added to the routing configuration.&lt;/p&gt;

&lt;h6&gt;
  
  
  --providers.docker.endpoint=tcp://socket_proxy:2375
&lt;/h6&gt;

&lt;p&gt;Instead of connecting directly to &lt;code&gt;unix:///var/run/docker.sock&lt;/code&gt; we are going to use the &lt;code&gt;socket_proxy&lt;/code&gt; container to be able to query the Docker endpoint as a security precaution.&lt;/p&gt;

&lt;h6&gt;
  
  
  --providers.docker.network=traefik_public
&lt;/h6&gt;

&lt;p&gt;All exposed services through Traefik are going to use by default the &lt;code&gt;traefik_public&lt;/code&gt; Docker network.&lt;/p&gt;

&lt;h5&gt;
  
  
  Whoami labels
&lt;/h5&gt;

&lt;p&gt;The Docker service &lt;code&gt;whoami&lt;/code&gt; is going to be exposed and only reachable through Traefik.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

  &lt;span class="na"&gt;whoami&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik/whoami:v1.7.1&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Explicitly instruct Traefik to expose this service&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
      &lt;span class="c1"&gt;# Router configuration&lt;/span&gt;
      &lt;span class="c1"&gt;## Listen to the `web` entrypoint&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.entrypoints=web&lt;/span&gt;
      &lt;span class="c1"&gt;## Rule based on the Host of the request&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.rule=Host(`whoami.karvounis.tutorial`)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.service=whoami_service&lt;/span&gt;
      &lt;span class="c1"&gt;# Service configuration&lt;/span&gt;
      &lt;span class="c1"&gt;## 80 is the port that the whoami container is listening to&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.services.whoami_service.loadbalancer.server.port=80&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h6&gt;
  
  
  traefik.enable=true
&lt;/h6&gt;

&lt;p&gt;Explicitly instructs Traefik to add it to the routing configuration.&lt;/p&gt;
&lt;h6&gt;
  
  
  traefik.http.routers.whoami_route.entrypoints=web
&lt;/h6&gt;

&lt;p&gt;The &lt;code&gt;whoami_route&lt;/code&gt; route accepts requests only from the &lt;code&gt;web&lt;/code&gt; entrypoint (port 80).&lt;/p&gt;
&lt;h6&gt;
  
  
  traefik.http.routers.whoami_route.rule=Host(&lt;code&gt;whoami.karvounis.tutorial&lt;/code&gt;)
&lt;/h6&gt;

&lt;p&gt;This label adds the Host rule. If a request's domain (host header value) is &lt;code&gt;whoami.karvounis.tutorial&lt;/code&gt; then this router becomes active and forwards the request to the service.&lt;/p&gt;
&lt;h6&gt;
  
  
  traefik.http.routers.whoami_route.service=whoami_service
&lt;/h6&gt;

&lt;p&gt;Service to use if the request matches the criteria of the &lt;code&gt;whoami_route&lt;/code&gt;.&lt;/p&gt;
&lt;h6&gt;
  
  
  traefik.http.services.whoami_service.loadbalancer.server.port=80
&lt;/h6&gt;

&lt;p&gt;The &lt;code&gt;whoami_service&lt;/code&gt; service is going to send the request to the port 80 of the container (the value 80 is the default value for this setting). Useful when the default container port that a service is listening to is not 80 (i.e. Portainer is listening to 9000 so in that case you would configure that service like this &lt;code&gt;traefik.http.services.portainer_service.loadbalancer.server.port=9000&lt;/code&gt;).&lt;/p&gt;
&lt;h4&gt;
  
  
  Complete configuration
&lt;/h4&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.7"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik:v2.6&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Entrypoints configuration&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--entrypoints.web.address=:80&lt;/span&gt;
      &lt;span class="c1"&gt;# Docker provider configuration&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker=true&lt;/span&gt;
      &lt;span class="c1"&gt;# Makes sure that services have to explicitly direct Traefik to expose them&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.exposedbydefault=false&lt;/span&gt;
      &lt;span class="c1"&gt;# Use the secure docker socket proxy&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.endpoint=tcp://socket_proxy:2375&lt;/span&gt;
      &lt;span class="c1"&gt;# Default docker network to use for connections to all containers&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.network=traefik_public&lt;/span&gt;
      &lt;span class="c1"&gt;# Logging levels are DEBUG, PANIC, FATAL, ERROR, WARN, and INFO.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--log.level=info&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;80:80&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik_public&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;socket_proxy&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;socket_proxy&lt;/span&gt;

  &lt;span class="c1"&gt;# https://github.com/traefik/whoami&lt;/span&gt;
  &lt;span class="na"&gt;whoami&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik/whoami:v1.7.1&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# Explicitly instruct Traefik to expose this service&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.enable=true&lt;/span&gt;
      &lt;span class="c1"&gt;# Router configuration&lt;/span&gt;
      &lt;span class="c1"&gt;## Listen to the `web` entrypoint&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.entrypoints=web&lt;/span&gt;
      &lt;span class="c1"&gt;## Rule based on the Host of the request&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.rule=Host(`whoami.karvounis.tutorial`)&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.routers.whoami_route.service=whoami_service&lt;/span&gt;
      &lt;span class="c1"&gt;# Service configuration&lt;/span&gt;
      &lt;span class="c1"&gt;## 80 is the port that the whoami container is listening to&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik.http.services.whoami_service.loadbalancer.server.port=80&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik_public&lt;/span&gt;

  &lt;span class="c1"&gt;# https://github.com/Tecnativa/docker-socket-proxy&lt;/span&gt;
  &lt;span class="c1"&gt;# Security-enhanced proxy for the Docker Socket&lt;/span&gt;
  &lt;span class="na"&gt;socket_proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tecnativa/docker-socket-proxy:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;NETWORKS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;SERVICES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;CONTAINERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;TASKS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock:ro&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;socket_proxy&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik_public&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;socket_proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Deploy the containers
&lt;/h3&gt;

&lt;p&gt;Deploy the containers by executing the following command:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Send a request to Traefik with the Host header set to &lt;code&gt;whoami.karvounis.tutorial&lt;/code&gt;. This request matches the &lt;code&gt;Host&lt;/code&gt; rule of the &lt;code&gt;whoami_route&lt;/code&gt; router and will be forwarded to the &lt;code&gt;whoami_service&lt;/code&gt; service. The response's &lt;code&gt;Hostname&lt;/code&gt; field is the ID of the &lt;code&gt;whoami&lt;/code&gt; Docker container.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Host: whoami.karvounis.tutorial"&lt;/span&gt; http://localhost/

Hostname: ed1b87c345ad
IP: 127.0.0.1
IP: 172.19.0.2
RemoteAddr: 172.19.0.3:49146
GET / HTTP/1.1
Host: whoami.karvounis.tutorial
User-Agent: curl/7.68.0
Accept: &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;
Accept-Encoding: &lt;span class="nb"&gt;gzip
&lt;/span&gt;X-Forwarded-For: 172.20.0.1
X-Forwarded-Host: whoami.karvounis.tutorial
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: f71bbf328ed6
X-Real-Ip: 172.20.0.1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By sending the following request, Traefik will forward the request to &lt;code&gt;whoami_service&lt;/code&gt; and will also forward the desired path &lt;code&gt;/api&lt;/code&gt; to the service. The response from the &lt;code&gt;whoami_service&lt;/code&gt; is the same response as above but in JSON.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Host: whoami.karvounis.tutorial"&lt;/span&gt; http://localhost/api

&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"hostname"&lt;/span&gt;:&lt;span class="s2"&gt;"ed1b87c345ad"&lt;/span&gt;,&lt;span class="s2"&gt;"ip"&lt;/span&gt;:[&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;,&lt;span class="s2"&gt;"172.19.0.2"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"headers"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Accept"&lt;/span&gt;:[&lt;span class="s2"&gt;"*/*"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"Accept-Encoding"&lt;/span&gt;:[&lt;span class="s2"&gt;"gzip"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"User-Agent"&lt;/span&gt;:[&lt;span class="s2"&gt;"curl/7.68.0"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"X-Forwarded-For"&lt;/span&gt;:[&lt;span class="s2"&gt;"172.20.0.1"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"X-Forwarded-Host"&lt;/span&gt;:[&lt;span class="s2"&gt;"whoami.karvounis.tutorial"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"X-Forwarded-Port"&lt;/span&gt;:[&lt;span class="s2"&gt;"80"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"X-Forwarded-Proto"&lt;/span&gt;:[&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"X-Forwarded-Server"&lt;/span&gt;:[&lt;span class="s2"&gt;"f71bbf328ed6"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,&lt;span class="s2"&gt;"X-Real-Ip"&lt;/span&gt;:[&lt;span class="s2"&gt;"172.20.0.1"&lt;/span&gt;&lt;span class="o"&gt;]}&lt;/span&gt;,&lt;span class="s2"&gt;"url"&lt;/span&gt;:&lt;span class="s2"&gt;"/api"&lt;/span&gt;,&lt;span class="s2"&gt;"host"&lt;/span&gt;:&lt;span class="s2"&gt;"whoami.karvounis.tutorial"&lt;/span&gt;,&lt;span class="s2"&gt;"method"&lt;/span&gt;:&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Try by yourself the following request&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Host: whoami.karvounis.tutorial"&lt;/span&gt; &lt;span class="s2"&gt;"http://localhost/data?size=1&amp;amp;unit=KB"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Alternatively, add the line &lt;code&gt;127.0.0.1 whoami.karvounis.tutorial&lt;/code&gt; to your &lt;code&gt;/etc/hosts&lt;/code&gt; file and visit the &lt;code&gt;http://whoami.karvounis.tutorial/&lt;/code&gt; URL from your browser.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scale whoami service to 3 containers
&lt;/h4&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker-compose up &lt;span class="nt"&gt;--scale&lt;/span&gt; &lt;span class="nb"&gt;whoami&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nt"&gt;-d&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above command will create 3 containers for the &lt;code&gt;whoami&lt;/code&gt; Docker service instead of just 1. Send the following request multiple times and see Traefik load balance the requests between the 3 containers (&lt;code&gt;Hostname&lt;/code&gt; keeps changing on every request).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Host: whoami.karvounis.tutorial"&lt;/span&gt; http://localhost/


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isn't that wonderful and automagical?&lt;/p&gt;

&lt;h2&gt;
  
  
  Final notes
&lt;/h2&gt;

&lt;p&gt;Congratulations! We successfully configured Traefik to run in Docker, listen for requests on port 80 and forward requests to the &lt;code&gt;whoami&lt;/code&gt; service! However, this is just a pretty basic Traefik configuration and the beginning of your Traefik journey. We are going to cover some more advanced topics in the next tutorial! Until next time!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can find me on &lt;a href="https://www.linkedin.com/in/karvounis/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://github.com/karvounis/" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>traefik</category>
      <category>devops</category>
      <category>docker</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
