<?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>Forem: Jawira Portugal</title>
    <description>The latest articles on Forem by Jawira Portugal (@jawira).</description>
    <link>https://forem.com/jawira</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%2F228582%2Ff9e0d331-fb8d-4229-aa14-720882adfe46.jpeg</url>
      <title>Forem: Jawira Portugal</title>
      <link>https://forem.com/jawira</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jawira"/>
    <language>en</language>
    <item>
      <title>Profiling a PHP script with XDebug</title>
      <dc:creator>Jawira Portugal</dc:creator>
      <pubDate>Tue, 07 Jun 2022 20:01:07 +0000</pubDate>
      <link>https://forem.com/jawira/profiling-a-php-script-with-xdebug-8o5</link>
      <guid>https://forem.com/jawira/profiling-a-php-script-with-xdebug-8o5</guid>
      <description>&lt;p&gt;Software profiling is a powerful technique when you want to optimize your code. Among other things, a profile snapshot will show you which parts of your software are the slower.&lt;/p&gt;

&lt;p&gt;In this article I will explain how to create a profile snapshot for a PHP script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;I assume you are using &lt;em&gt;Ubuntu&lt;/em&gt; and you already have PHP installed. Please also install &lt;em&gt;XDebug 3&lt;/em&gt; and &lt;em&gt;KCachegrind&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;php-xdebug
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;kcachegrind
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create profile file
&lt;/h2&gt;

&lt;p&gt;As an example, I will profile tests from &lt;a href="https://github.com/jawira/plantuml-encoding"&gt;jawira/plantuml-encoding&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git clone https://github.com/jawira/plantuml-encoding.git
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;plantuml-encoding
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;php tests/vanilla.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the following command to profile &lt;code&gt;tests/vanilla.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;php &lt;span class="nt"&gt;-dxdebug&lt;/span&gt;.mode&lt;span class="o"&gt;=&lt;/span&gt;profile &lt;span class="nt"&gt;-dxdebug&lt;/span&gt;.output_dir&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; tests/vanilla.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the execution is finished, a new profile snapshot will be created. This profile file has the following name pattern &lt;code&gt;cachegrind.out.xxxxx&lt;/code&gt; (where &lt;code&gt;xxxxx&lt;/code&gt; is a number).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bYLYwkZp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vv7jue687nrg0iliv4ks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bYLYwkZp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vv7jue687nrg0iliv4ks.png" alt="terminal screenshot" width="880" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;XDebug&lt;/em&gt; can be configured in &lt;code&gt;php.ini&lt;/code&gt;. Here we have configured &lt;em&gt;XDebug&lt;/em&gt; &lt;em&gt;on-the-fly&lt;/em&gt; passing &lt;code&gt;php.ini&lt;/code&gt; configuration through the terminal.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-dxdebug.mode=profile&lt;/strong&gt;: This option makes &lt;code&gt;profile mode&lt;/code&gt; enabled for this command.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-dxdebug.output_dir=.&lt;/strong&gt;: Save profile snapshots in current dir "&lt;code&gt;.&lt;/code&gt;", otherwise snapshots are saved in &lt;code&gt;/tmp&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case &lt;code&gt;profiling mode&lt;/code&gt; is ephemeral, but it can be a problem if you are activating profiling by other means (for example directly editing &lt;code&gt;php.ini&lt;/code&gt; file). Profile snapshots can take a LOT of disk space, never leave profile mode permanently enabled. &lt;/p&gt;

&lt;h2&gt;
  
  
  Opening profile file
&lt;/h2&gt;

&lt;p&gt;To visualize your profile snapshot, simply open the snapshot (in our case &lt;code&gt;cachegrind.out.14476&lt;/code&gt;) with &lt;em&gt;KCachegrind&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iO54a6wy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sj19zq92e7yuidjcmr8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iO54a6wy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sj19zq92e7yuidjcmr8s.png" alt="KCachegrind screenshot" width="880" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reading and interpretation of profiling files are beyond the scope of this article, yet I recommend you to see this video &lt;a href="https://www.youtube.com/watch?v=h-0HpCblt3A"&gt;https://www.youtube.com/watch?v=h-0HpCblt3A&lt;/a&gt; presenting KCachegrind.&lt;/p&gt;

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

&lt;p&gt;Creating a profile snapshot is easy if you understand how to configure &lt;em&gt;XDebug&lt;/em&gt; properly. Using &lt;code&gt;-d&lt;/code&gt; options is very convenient technique to enable profiling from the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://xdebug.org/docs/profiler"&gt;https://xdebug.org/docs/profiler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://kcachegrind.github.io/html/Documentation.html"&gt;http://kcachegrind.github.io/html/Documentation.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>php</category>
      <category>xdebug</category>
      <category>profiling</category>
    </item>
    <item>
      <title>Defining dynamic Host rule in Traefik v2</title>
      <dc:creator>Jawira Portugal</dc:creator>
      <pubDate>Mon, 02 May 2022 18:44:42 +0000</pubDate>
      <link>https://forem.com/jawira/defining-dynamic-host-rule-in-traefik-v2-4doj</link>
      <guid>https://forem.com/jawira/defining-dynamic-host-rule-in-traefik-v2-4doj</guid>
      <description>&lt;p&gt;&lt;a href="https://traefik.io/traefik/" rel="noopener noreferrer"&gt;Traefik&lt;/a&gt; is a reverse http proxy, it works specially well with &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;docker&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;docker-compose&lt;/a&gt; environments. Traefik will receive all your incoming web requests and redirect them to Docker containers.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r9hfv4swsla88heeoal.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9r9hfv4swsla88heeoal.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to redirect your requests, Traefik will use a router to identify the appropriate web server. &lt;/p&gt;

&lt;p&gt;In this article I show you how I configured a default "Host rule" for my development environment. This rule will automatically add a rule for any service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;http://&amp;lt;service&amp;gt;.&amp;lt;project&amp;gt;.localhost&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I assume you already have some experience with Docker and Traefik.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traefik configuration
&lt;/h2&gt;

&lt;p&gt;First install Traefik. Let's create a new project with the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;traefik/
└── docker-compose.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You only need one single file to start using Traefik. This is the content of &lt;code&gt;traefik/docker-compose.yaml&lt;/code&gt;:&lt;br&gt;
&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&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.7&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;always&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--api.insecure=true'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--providers.docker.network=traefik_default'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--providers.docker.defaultRule=Host(`{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;index&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.Labels&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"com.docker.compose.service"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}.{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;index&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.Labels&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"com.docker.compose.project"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}.localhost`)'&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;traefik.http.services.traefik-traefik.loadBalancer.server.port=8080'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true'&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="s1"&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8080:8080'&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock'&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;default&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;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the most important command option when creating dynamic rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--providers.docker.defaultRule=Host(`{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;index&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.Labels&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"com.docker.compose.service"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}.{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;index&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;.Labels&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"com.docker.compose.project"&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}.localhost`)'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see what the previous line does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;--providers.docker.defaultRule&lt;/strong&gt;: this is the rule to be used if container doesn't define one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Host()&lt;/strong&gt;: the requested domain will be used for routing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;{{ index .Labels "com.docker.compose.service" }}&lt;/code&gt;&lt;/strong&gt;: this represents the service name, the one you define in &lt;code&gt;docker-compose.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;{{ index .Labels "com.docker.compose.project" }}&lt;/code&gt;&lt;/strong&gt;: this placeholder will be replaced with project name. By default, the project name is the directory name, you can also specify this value with &lt;code&gt;-p &amp;lt;project&amp;gt;&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;Finally &lt;strong&gt;&lt;code&gt;.localhost&lt;/code&gt;&lt;/strong&gt; is &lt;a href="https://datatracker.ietf.org/doc/html/rfc2606" rel="noopener noreferrer"&gt;a reserved domain&lt;/a&gt;, it will always point to the loopback address &lt;strong&gt;&lt;code&gt;127.0.0.1&lt;/code&gt;&lt;/strong&gt;. Using &lt;code&gt;.localhost&lt;/code&gt;, you will not need to add your development domains to &lt;code&gt;/etc/hosts&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start Traefik with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker compose &lt;span class="nt"&gt;-p&lt;/span&gt; traefik up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traefik is up and running now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a sample project
&lt;/h2&gt;

&lt;p&gt;We will create a demo project to check if our dynamic rules work properly. This is the structure of &lt;code&gt;foo&lt;/code&gt; project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;foo/
└── docker-compose.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define an Apache server within &lt;code&gt;foo/docker-compose.yaml&lt;/code&gt;:&lt;br&gt;
&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;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;web&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;httpd&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="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;default&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;traefik_default&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;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik_default&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;p&gt;Let's execute our demo project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;docker compose &lt;span class="nt"&gt;-p&lt;/span&gt; foo up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we open &lt;code&gt;http://web.foo.localhost&lt;/code&gt; we will see Apache's welcome message:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4o5h8hc8t7536as6nrb.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4o5h8hc8t7536as6nrb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using a custom rule
&lt;/h2&gt;

&lt;p&gt;We can also specify a custom rule for a service, this custom rule will override the default rule. &lt;/p&gt;

&lt;p&gt;For example we want to use &lt;code&gt;my-foo.localhost&lt;/code&gt;, to do so we simple add a new &lt;code&gt;label&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;# ...
  web:
    image: httpd
    labels:
      - traefik.enable=true
&lt;span class="gi"&gt;+     - traefik.http.routers.foo-project.rule=Host(`my-foo.localhost`)
&lt;/span&gt;# ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make changes take effect we have to launch again our project using &lt;code&gt;docker compose -p foo up -d&lt;/code&gt;. This is the result:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2pp617uubag3we2y3bn.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2pp617uubag3we2y3bn.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see everything works as expected.&lt;/p&gt;

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

&lt;p&gt;Traefik is a highly configurable reverse proxy. You only need one line of code to have dynamic domains, these domains are well suited for development environments.&lt;/p&gt;

&lt;p&gt;If you use &lt;code&gt;.localhost&lt;/code&gt; tld, you won't need to declare your domains within &lt;code&gt;/etc/hosts&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>traefik</category>
      <category>docker</category>
      <category>compose</category>
    </item>
  </channel>
</rss>
