{"id":1552,"date":"2024-11-01T07:00:18","date_gmt":"2024-11-01T07:00:18","guid":{"rendered":"https:\/\/blog.ssdnodes.com\/blog\/?p=1552"},"modified":"2025-05-15T15:34:13","modified_gmt":"2025-05-15T15:34:13","slug":"traefik-as-a-reverse-proxy-for-multiple-hosts-docker-compose","status":"publish","type":"post","link":"https:\/\/www.ssdnodes.com\/blog\/traefik-as-a-reverse-proxy-for-multiple-hosts-docker-compose\/","title":{"rendered":"Using Traefik as a Reverse Proxy for Multiple Hosts with Docker Compose"},"content":{"rendered":"<p>This guide will cover how to use Traefik as a reverse proxy to manage multiple hosts with Docker Compose.<\/p>\n<p>Suppose you had deployed several microservices using Docker and you want to connect these microservices to the outside world. You will probably use some reverse proxy solution that will act as a frontend for these microservices. <a href=\"https:\/\/www.ssdnodes.com\/blog\/how-to-use-nginx-as-a-reverse-proxy-with-ssl-tutorial\/\" target=\"_blank\" rel=\"noopener noreferrer\">Nginx is the most popular and efficient reverse proxy solution<\/a>, but it was written before container technology (like <a href=\"https:\/\/www.ssdnodes.com\/blog\/self-hosting-handbook\/\" target=\"_blank\" rel=\"noopener noreferrer\">Docker<\/a>) became so popular. The modern solution for hosting multiple hosts with Docker is now Traefik.<\/p>\n<h2>What is Traefik?<\/h2>\n<p><a href=\"https:\/\/Traefik.io\/\" target=\"_blank\" rel=\"noopener\">Traefik<\/a> is a modern reverse proxy solution written in GO to meet modern containerized challenges.<\/p>\n<blockquote><p>Unlike a traditional reverse proxy, which requires manual configuration, Traefik uses service discovery to dynamically configure routing. Traefik supports all major protocols, leveraging a rich set of middleware for load balancing, rate-limiting, circuit-breakers, mirroring, authentication, and more. Traefik also supports SSL termination and works with ACME providers (like Let\u2019s Encrypt) for automatic certificate generation. <a href=\"https:\/\/traefik.io\/traefik\/\" target=\"_blank\" rel=\"noopener\">Source.<\/a><\/p><\/blockquote>\n<p>Traefik was developed with containerized technology in mind, which means there\u2019s a lot of new features available in comparison with other reverse proxy solutions. When running, Traefik does the following and more:<\/p>\n<ul>\n<li>Dynamically updates the configuration and loads it without a restart.<\/li>\n<li>Load balances requests from the outside world using multiple available algorithms.<\/li>\n<li>Enables HTTPS for microservices using Let\u2019s Encrypt.<\/li>\n<li>Provides a clean web UI.<\/li>\n<li>Supports for WebSocket, HTTP\/2, GRPC.<\/li>\n<li>Provides metrics to Rest, Prometheus, Datadog, Statsd, InfluxDB.<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-10970 size-full\" src=\"https:\/\/www.ssdnodes.com\/wp-content\/uploads\/2020\/03\/Traefik-Post.jpg\" alt=\"Traefik Reverse Proxy for Multiple Hosts with Docker Compose\" width=\"600\" height=\"400\" srcset=\"https:\/\/www.ssdnodes.com\/wp-content\/uploads\/2020\/03\/Traefik-Post.jpg 600w, https:\/\/www.ssdnodes.com\/wp-content\/uploads\/2020\/03\/Traefik-Post-300x200.jpg 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<h2>Why Use Traefik as a Reverse Proxy for Multiple Hosts?<\/h2>\n<p>Say, for example, you want to remove one of the microservices from the container or change its port, and, as a result, you have to edit the Nginx configuration file to reflect the new container settings. Now, consider another situation where you add, delete, or scale the microservices application several times in a day\u2014now, you\u2019re editing the routes and other settings several times in the reverse proxy configuration file.<\/p>\n<p>In this article, we will check how to install Traefik and configure it in a standalone <em>and<\/em> Dockerized environment, and then give examples of connecting it to your microservices in the backend.<\/p>\n<h2><a id=\"Prerequisites_21\"><\/a>Prerequisites to Install Traefik<\/h2>\n<ul>\n<li>A VPS running Ubuntu 24.04. Get your Linux VPS hosting from a reputable and trustworthy provider like <strong>SSD Nodes<\/strong>. We offer powerful Ubuntu servers and the best deals. Take a look at our <a href=\"https:\/\/www.ssdnodes.com\/blog\/cheap-linux-vps-comparison-report\/\" target=\"_blank\" rel=\"noopener\">offerings<\/a>\u00a0and prepare for your mind to be blown \ud83e\udd2f.<\/li>\n<li>A non-root, <code>sudo<\/code>-enabled user. If you only have a <code>root<\/code> user, see our <a href=\"https:\/\/www.ssdnodes.com\/blog\/connecting-vps-ssh-security\/\">SSH tutorial<\/a> for details on creating new users.<\/li>\n<li>A working Docker installation\u2014for information about how to install Docker, check out our <a href=\"https:\/\/www.ssdnodes.com\/blog\/getting-started-docker-vps\/\">getting started with Docker tutorial<\/a>.<\/li>\n<\/ul>\n<h2><a id=\"Step_2_Installing_nonDockerized_backend_applications_45\"><\/a>Using Traefik without Docker<\/h2>\n<p>Our first goal is to install Traefik\u00a0 and use it to route a few applications (backend) using Traefik configuration without Dockerizing them. To do that, we\u2019ll install <a href=\"https:\/\/www.ssdnodes.com\/blog\/installing-lamp-on-ubuntu-22-04-lts-jammy-jellyfish\/\">Apache<\/a> and <a href=\"https:\/\/www.ssdnodes.com\/blog\/how-to-install-lemp-on-ubuntu-24-04\/\">Nginx<\/a> and configure them to use different ports, as they will act as a backend.<\/p>\n<p>First, update your system package index:<\/p>\n<pre><code>$ sudo apt update<\/code><\/pre>\n<p>Install Apache:<\/p>\n<pre><code>$ sudo apt install apache2\r\n<\/code><\/pre>\n<p>Change the port number to <code>8083<\/code> from <code>80<\/code> in <code>\/etc\/apache2\/ports.conf<\/code> and restart Apache.<\/p>\n<pre><code>$ sudo nano \/etc\/apache2\/ports.conf\r\n$ sudo systemctl restart apache2\r\n<\/code><\/pre>\n<p>Next, install Nginx:<\/p>\n<pre><code>$ sudo apt install nginx<\/code><\/pre>\n<p>Create a custom welcome page for the Nginx server to distinguish between the two servers:<\/p>\n<pre><code class=\"language-bash\">$ sudo mkdir \/var\/www\/nginx_html\r\n$ sudo echo '&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;body&gt;&lt;h1&gt;Welcome to My Nginx Page&lt;\/h1&gt;&lt;\/body&gt;&lt;\/html&gt;' | sudo tee \/var\/www\/nginx_html\/index.html\r\n<\/code><\/pre>\n<p>Next, edit the default Nginx configuration file:<\/p>\n<pre><code class=\"language-bash\">$ sudo nano \/etc\/nginx\/sites-available\/default \r\n<\/code><\/pre>\n<p>Point Nginx to the new <code>\/var\/www\/nginx_html<\/code> directory, and the <code>8082<\/code> port number:<\/p>\n<pre><code class=\"language-bash\">server {\r\n        listen <mark>8082<\/mark> default_server;\r\n        listen [::]:<mark>8082<\/mark> default_server;\r\n        # ...\r\n        # ...\r\n        # ...\r\n        \r\n        root <mark>\/var\/www\/nginx_html<\/mark>;\r\n        # ...\r\n        # ...\r\n        # ...\r\n        }\r\n<\/code><\/pre>\n<p>Next, restart Nginx:<\/p>\n<pre><code class=\"language-bash\">$ sudo systemctl restart nginx<\/code><!-- notionvc: d3a2101e-ca2c-454c-a670-597fa8ab1754 --><\/pre>\n<p>Now both Apache and Nginx will be available in the port number <code>8083<\/code> and <code>8082<\/code>, respectively.<\/p>\n<h3>Step 1: Install Traefik<\/h3>\n<p>To install Traefik as a standalone environment, we need to download the binary and edit the Traefik configuration file and rules files.<br \/>\nDownload the Traefik binary from the <a href=\"https:\/\/github.com\/traefik\/traefik\/releases\" target=\"_blank\" rel=\"noopener\">releases page<\/a>:<\/p>\n<pre><code class=\"language-bash\">$ wget https:\/\/github.com\/traefik\/traefik\/releases\/download\/v3.1.4\/traefik_v3.1.4_linux_amd64.tar.gz\r\n<\/code><\/pre>\n<p>Remember to replace <code>v3.1.4<\/code> with the latest release, or another binary that is compatible with your system.<\/p>\n<p>Check the integrity of the downloaded file and compare it to the value in the <code>traefik_v3.1.4_checksums.txt<\/code> file:<\/p>\n<pre><code class=\"language-bash\">$ sha256sum .\/traefik_v3.1.4_linux_amd64.tar.gz\r\n<\/code><\/pre>\n<p>Next, extract the compressed file:<\/p>\n<pre><code class=\"language-bash\">$ tar -zxvf traefik_v3.1.4_linux_amd64.tar.gz\r\n<\/code><\/pre>\n<p>You can now use <code>.\/traefik<\/code> to run Traefik configurations.<\/p>\n<h3>Step 2: Traefik Configuration<\/h3>\n<p>To host multiple websites with Traefik, you\u2019ll need to create a configuration file that routes each domain to the corresponding port.<\/p>\n<p>First, we\u2019ll create a <code>traefik.yml<\/code> file that gets automatically detected by Traefik:<\/p>\n<pre><code class=\"language-bash\">log:\r\n  level: \"DEBUG\"\r\n\r\nentryPoints:\r\n  web:\r\n   address: \":80\"\r\n\r\nproviders:\r\n  file:\r\n    filename: \".\/rules.yml\"\r\n    watch: true\r\n<\/code><\/pre>\n<p>In this <code>traefik.yml<\/code> file, you have the following:<\/p>\n<ul>\n<li><strong><code>log<\/code>:<\/strong> Sets log level to <code>DEBUG<\/code> for detailed output.<\/li>\n<li><strong><code>entryPoints<\/code>:<\/strong> Defines <code>web<\/code> entry point to listen on port <code>80<\/code> for HTTP traffic.<\/li>\n<li><strong><code>providers<\/code>:<\/strong> This tells Traefik to load dynamic configuration (such as routes and services) from the <code>rules.yml<\/code> file, and watch for changes.<\/li>\n<\/ul>\n<h3>Step 3: Set up Traefik Rules<\/h3>\n<p>Next, create a <code>rules.yml<\/code> file to define dynamic routing rules:<\/p>\n<pre><code class=\"language-bash\">http:\r\n  routers:\r\n    router1:\r\n      rule: \"Host(`nginx.example.com`)\"\r\n      service: service1\r\n      entryPoints:\r\n        - web\r\n    router2:\r\n      rule: \"Host(`apache.example.com`)\"\r\n      service: service2\r\n      entryPoints:\r\n        - web\r\n\r\n  services:\r\n    service1:\r\n      loadBalancer:\r\n        servers:\r\n          - url: \"http:\/\/127.0.0.1:8082\"\r\n    service2:\r\n      loadBalancer:\r\n        servers:\r\n          - url: \"http:\/\/127.0.0.1:8083\"\r\n<\/code><\/pre>\n<p>Here, you define<strong><code>routers<\/code><\/strong> to define traffic rules and route them to services:<\/p>\n<ul>\n<li><code>router1<\/code>: Routes traffic requests for <code>nginx.example.com<\/code> to <code>service1<\/code>.<\/li>\n<li><code>router2<\/code>: Routes traffic requests for <code>apache.example.com<\/code> to <code>service2<\/code>.<\/li>\n<\/ul>\n<p>The services are defined as follows:<\/p>\n<ul>\n<li><code>service1<\/code>: Forwards traffic to the Nginx server at <code>http:\/\/127.0.0.1:8082<\/code>.<\/li>\n<li><code>service2<\/code>: Forwards traffic to Apache server at <code>http:\/\/127.0.0.1:8083<\/code>.<\/li>\n<\/ul>\n<p>Both routers listen on the <code>web<\/code> entry point, which was defined in the <code>traefik.yml<\/code> file.<\/p>\n<p>Make sure you are in the <code>Traefik<\/code> directory that hosts both the Traefik binary and the <code>traefik.yml<\/code> file, then run the following command:<\/p>\n<pre><code class=\"language-bash\">$ .\/traefik\r\n<\/code><\/pre>\n<p>Now, if you navigate to your domain names, you should see two different welcome pages, one for Nginx and one for Apache:<\/p>\n<pre><code class=\"language-bash\">http:\/\/nginx.example.com\/\r\nhttp:\/\/apache.example.com\/\r\n<\/code><\/pre>\n<p>With this, you now have two websites on one server with Traefik as a proxy. However, these two websites are served through HTTP and are not secured with HTTPS. We\u2019ll fix this in the next section and add a Let\u2019s Encrypt certificate to both domains.<\/p>\n<h3>Step 4: Using TLS in Traefik with Let\u2019s Encrypt<\/h3>\n<p>To use Let\u2019s Encrypt with your Traefik configuration, edit <code>traefik.yml<\/code> by adding a <code>websecure<\/code> entry point that listens on port <code>443<\/code> , which is the default HTTPS port, and a <code>certificatesResolvers<\/code> section to define how the Let\u2019s Encrypt certificate will be resolved:<\/p>\n<pre><code class=\"language-bash\">log:\r\n  level: \"DEBUG\"\r\n\r\nentryPoints:\r\n  web:\r\n   address: \":80\"\r\n  <mark>websecure:\r\n   address: \":443\"<\/mark>\r\n\r\nproviders:\r\n  file:\r\n    filename: \".\/rules.yml\"\r\n    watch: true\r\n\r\n<mark>certificatesResolvers:\r\n  myresolver:\r\n    acme:\r\n      email: \"your_email@example.com\"\r\n      storage: \"acme.json\"\r\n      httpChallenge:\r\n        entryPoint: web<\/mark>\r\n\r\nproviders:\r\n  file:\r\n    filename: \".\/rules.yml\"\r\n    watch: true\r\n<\/code><\/pre>\n<p>Next, update <code>rules.yml<\/code> by adding the <code>websecure<\/code> entry point and a <code>tls<\/code> option that uses the <code>myresolver<\/code> certificate resolver you defined in the <code>traefik.yml<\/code> file earlier, in addition to a <code>tlsoptions<\/code> field that specifies the TLS version.<\/p>\n<pre><code class=\"language-bash\">http:\r\n  routers:\r\n    router1:\r\n      rule: \"Host(`app1.your_domain.com`)\"\r\n      service: service1\r\n      entryPoints:\r\n        - web\r\n        <mark>- websecure\r\n      tls:\r\n        certResolver: myresolver\r\n        options: tlsoptions<\/mark>\r\n\r\n    router2:\r\n      rule: \"Host(`app2.your_domain.com`)\"\r\n      service: service2\r\n      entryPoints:\r\n        - web\r\n        <mark>- websecure\r\n      tls:\r\n        certResolver: myresolver\r\n        options: tlsoptions<\/mark>\r\n\r\n  services:\r\n    service1:\r\n      loadBalancer:\r\n        servers:\r\n          - url: \"http:\/\/127.0.0.1:8082\"\r\n    service2:\r\n      loadBalancer:\r\n        servers:\r\n          - url: \"http:\/\/127.0.0.1:8083\"\r\n<mark>tls:\r\n  options:\r\n    tlsoptions:\r\n      minVersion: VersionTLS12<\/mark>\r\n<\/code><\/pre>\n<p>&nbsp;<\/p>\n<p>Now, you can start Traefik again\u2014but remember to kill previous instances of it first.<\/p>\n<pre><code>$ .\/traefik<\/code><\/pre>\n<p>With this, you are now hosting two different web services via HTTPS with Traefik. Next, you\u2019ll learn how to use Traefik as a load balancer.<\/p>\n<p><!-- notionvc: edf67982-543b-4459-b19d-2146e1df9fb0 --><\/p>\n<h3>Step 5: Using Traefik as a Load Balancer<\/h3>\n<p><!-- notionvc: 3e8eeb2c-8148-4eab-b26e-72a9ea6cc4c9 --><\/p>\n<p><!-- notionvc: a5f82f6f-e425-4bc3-9614-ca7de0b72040 -->With little modification to the above rules file, we can make Traefik to act as a load balancer between both Apache and Nginx instances.<\/p>\n<pre><code>$ nano rules.yml\r\n<\/code><\/pre>\n<p>You can replace the file\u2019s contents with the following:<\/p>\n<pre><code class=\"language-bash\">http:\r\n  routers:\r\n    router1:\r\n      rule: \"Host(`your_domain.com`)\"\r\n      service: service1\r\n      entryPoints:\r\n        - web\r\n        - websecure\r\n      tls:\r\n        certResolver: myresolver\r\n        options: tlsoptions\r\n\r\n  services:\r\n    service1:\r\n      loadBalancer:\r\n        servers:\r\n          - url: \"http:\/\/127.0.0.1:8082\"\r\n            weight: 2\r\n          - url: \"http:\/\/127.0.0.1:8083\"\r\n            weight: 1\r\n\r\ntls:\r\n  options:\r\n    tlsoptions:\r\n      minVersion: VersionTLS12\r\n<\/code><\/pre>\n<p>Weight determines the proportion of traffic each server will receive. In this example:<\/p>\n<ul>\n<li>The Nignx server at <code>http:\/\/127.0.0.1:8082<\/code> has a weight of <code>2<\/code>.<\/li>\n<li>The Apache server at <code>http:\/\/127.0.0.1:8083<\/code> has a weight of <code>1<\/code>.<\/li>\n<\/ul>\n<p>This means that for every 3 requests, <strong>2 will go to<\/strong> <code>http:\/\/127.0.0.1:8082<\/code> and <strong>1 will go to<\/strong> <code>http:\/\/127.0.0.1:8083<\/code>.<\/p>\n<p><!-- notionvc: d3fc948e-c63c-42ab-9ba0-8e592af5ed1c --><\/p>\n<p>Now, you can start Traefik again\u2014but remember you have to kill previous instances of it first.<\/p>\n<pre><code>$ .\/traefik<\/code><\/pre>\n<p>Use your browser to visit the domain name that you entered into the <code>rules.yml<\/code> file and hit refresh. You\u2019ll find that Traefik is both proxying load balancing the Apache and Nginx backends.<\/p>\n<p>Now, let\u2019s look at this same process, but using Docker, docker-compose, and containerized\/Dockerized microservices, which is likely how many of you will end up using Traefik.<\/p>\n<h2>Using Traefik with Docker Compose<\/h2>\n<h3><a id=\"Step_1_Install_Docker_28\"><\/a>Step 1: Traefik Reverse Proxy Example for Docker<\/h3>\n<p>In this section, we'll explore an example of a Traefik reverse proxy with Docker compose.<\/p>\n<p>First, let\u2019s create a <code>docker-compose.yml<\/code> file, in which we will define services for Traefik and the other two microservices\u2014Apache and Nginx, just like before.<\/p>\n<pre><code>$ nano docker-compose.yml\r\n<\/code><\/pre>\n<p>Add the following:<\/p>\n<pre><code class=\"language-bash\">version: '3'\r\nservices:\r\n  reverse-proxy:\r\n    image: traefik:latest\r\n    command: --configFile=\/etc\/traefik\/traefik.yml\r\n    ports:\r\n      - \"80:80\"       # HTTP\r\n      - \"443:443\"     # HTTPS\r\n      - \"8080:8080\"   # Traefik dashboard\r\n    volumes:\r\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock\r\n      - .\/traefik.yml:\/etc\/traefik\/traefik.yml\r\n      - .\/acme.json:\/acme.json\r\n    networks:\r\n      - traefik\r\n\r\n  apache:\r\n    image: httpd:latest\r\n    labels:\r\n      - \"traefik.enable=true\"\r\n      - \"traefik.http.routers.apache.rule=Host(`apache.example.com`)\"\r\n      - \"traefik.http.routers.apache.entrypoints=web,websecure\"\r\n      - \"traefik.http.routers.apache.tls.certresolver=myresolver\"\r\n      - \"traefik.http.services.apache.loadbalancer.server.port=80\"\r\n    networks:\r\n      - traefik\r\n\r\n  nginx:\r\n    image: nginx:latest\r\n    labels:\r\n      - \"traefik.enable=true\"\r\n      - \"traefik.http.routers.nginx.rule=Host(`nginx.example.com`)\"\r\n      - \"traefik.http.routers.nginx.entrypoints=web,websecure\"\r\n      - \"traefik.http.routers.nginx.tls.certresolver=myresolver\"\r\n      - \"traefik.http.services.nginx.loadbalancer.server.port=80\"\r\n    networks:\r\n      - traefik\r\n\r\nnetworks:\r\n  traefik:\r\n    external: true\r\n<\/code><\/pre>\n<p><!-- notionvc: e761d480-c3f0-49dc-94ab-0ff1da6d0bd2 --><\/p>\n<p>Three services have been defined in the above <code>docker-compose.yml<\/code> file, and they are <code class=\"language-bash\">reverse-proxy<\/code>, <code>apache<\/code> and <code>nginx<\/code>.<\/p>\n<p>In the port section, <code>8080<\/code> is the port used by Traefik for its web interface and port <code>80<\/code>is used for all default HTTP requests. In the volume section, the Docker socket is accessed by Traefik to route requests to the right container.<\/p>\n<p>We need to knit all the three services together so that they can communicate with each other, which is why we created the <code>traefik<\/code> network at the end of the file.<\/p>\n<p>As for the services, we have the following:<\/p>\n<ul>\n<li><strong>reverse-proxy service<\/strong>: This is the Traefik service acting as a reverse proxy, with ports for HTTP, HTTPS, and the Traefik dashboard.<\/li>\n<li><strong>Apache and Nginx services<\/strong>: Both have labels that define routing rules for Traefik:\n<ul>\n<li><code>traefik.http.routers.[service].rule<\/code>: Routes traffic based on the <code>Host<\/code>.<\/li>\n<li><code>traefik.http.routers.[service].entrypoints<\/code>: Defines which entry points to use (<code>web<\/code> for HTTP, <code>websecure<\/code> for HTTPS).<\/li>\n<li><code>traefik.http.routers.[service].tls.certresolver<\/code>: Configures TLS with the <code>myresolver<\/code> certificate resolver, which we\u2019ll define in the <code>traefik.yml<\/code> file next section.<\/li>\n<li><code>traefik.http.services.[service].loadbalancer.server.port<\/code>: Defines the internal port for each service.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3>Step 2: Run Traefik using Docker<\/h3>\n<p>First, create a new <code>traefik.yml<\/code> file. This is the configuration file referenced inside <code>docker-compose.yml<\/code> in the previous section. This Traefik configuration file defines the entry points, certificate resolver, and sets the provider as Docker:<\/p>\n<pre><code class=\"language-bash\">log:\r\n  level: \"DEBUG\"  # Set log level to DEBUG for detailed logs\r\n\r\nentryPoints:\r\n  web:\r\n    address: \":80\"\r\n  websecure:\r\n    address: \":443\"\r\n  traefik:\r\n    address: \":8080\"  # Dashboard entry point\r\n\r\ncertificatesResolvers:\r\n  myresolver:\r\n    acme:\r\n      email: your_email@example.com\r\n      storage: acme.json\r\n      httpChallenge:\r\n        entryPoint: web\r\n\r\nproviders:\r\n  docker:\r\n    exposedByDefault: false\r\n#api:\r\n#  dashboard: true  # Enable the Traefik dashboard\r\n#  insecure: true   # Allow access to the dashboard without authentication (for development)\r\n<\/code><\/pre>\n<p>Here, you have the following:<\/p>\n<ul>\n<li><strong>EntryPoints<\/strong>: Defines the ports that Traefik will listen to for HTTP (<code>:80<\/code>) and HTTPS (<code>:443<\/code>) traffic.<\/li>\n<li><strong>certificatesResolvers<\/strong>: This uses the <strong>ACME protocol<\/strong> to automatically generate SSL certificates for the domains (replace <code>your-email@example.com<\/code> with your real email). The great thing about Traefik is that these certificates are dynamic, meaning that if you add a new domain or subdomain to <code>docker-compose.yml<\/code>, Traefik will automatically fetch the key\/certificate and store them in <code>acme.json<\/code>.\n<ul>\n<li>The <code>httpChallenge<\/code> is configured to solve TLS challenges over HTTP (port 80).<\/li>\n<\/ul>\n<\/li>\n<li><strong>providers.docker<\/strong>: Enables Docker as the provider for dynamic routing, but <code>exposedByDefault: false<\/code> ensures that only services explicitly enabled via labels will be exposed by Traefik.<\/li>\n<\/ul>\n<p>Make sure <strong>Traefik has access<\/strong> to your <code>acme.json<\/code> file, which stores certificate information:<\/p>\n<pre><code class=\"language-bash\">$ touch acme.json\r\n$ chmod 600 acme.json\r\n<\/code><\/pre>\n<p>Create the <code>traefik<\/code> network:<\/p>\n<pre><code class=\"language-mathematica\">$ docker network create traefik\r\n<\/code><\/pre>\n<p>Start the services with Docker Compose:<\/p>\n<pre><code class=\"language-mathematica\">$ docker compose up -d\r\n<\/code><\/pre>\n<p>You should see the following output:<\/p>\n<pre><code class=\"language-mathematica\">[+] Running 19\/19\r\n \u2714 reverse-proxy Pulled                                                                             19.4s\r\n   \u2714 43c4264eed91 Pull complete                                                                      3.0s\r\n   \u2714 eee3b43fedbd Pull complete                                                                      3.5s\r\n   \u2714 e951b536ebf8 Pull complete                                                                      5.9s\r\n   \u2714 188dd7af1135 Pull complete                                                                      3.9s\r\n \u2714 apache Pulled                                                                                    16.2s\r\n   \u2714 62dd86107c65 Pull complete                                                                      1.3s\r\n   \u2714 4f4fb700ef54 Pull complete                                                                      3.8s\r\n   \u2714 509789394c2a Pull complete                                                                      3.8s\r\n \u2714 nginx Pulled                                                                                     18.7s\r\n   \u2714 a2318d6c47ec Pull complete                                                                      0.8s\r\n   \u2714 095d327c79ae Pull complete                                                                      1.5s\r\n   \u2714 24b3fdc4d1e3 Pull complete                                                                      2.8s\r\n   \u2714 3122471704d5 Pull complete                                                                      3.2s\r\n<\/code><\/pre>\n<p>With this, you\u2019ll have two HTTPS-enabled applications served by Traefik at <code>https:\/\/apache.your_domain.com\/<\/code> and <code>https:\/\/nginx.your_domain.com\/<\/code><\/p>\n<h3>Step 3: Enable the Traefik Dashboard<\/h3>\n<p>If you want to access the Traefik dashboard, uncomment the last two lines in the <code>traefik.yml<\/code> file:<\/p>\n<pre><code class=\"language-yaml\">log:\r\n  level: \"DEBUG\"\r\n\r\nentryPoints:\r\n  web:\r\n    address: \":80\"\r\n  websecure:\r\n    address: \":443\"\r\n  traefik:\r\n    address: \":8080\"  # Dashboard entry point\r\n\r\ncertificatesResolvers:\r\n  myresolver:\r\n    acme:\r\n      email: your-email@example.com\r\n      storage: acme.json\r\n      httpChallenge:\r\n        entryPoint: web\r\n\r\nproviders:\r\n  docker:\r\n    exposedByDefault: false\r\n\r\n<mark>api:\r\n  dashboard: true  # Enable the Traefik dashboard\r\n  insecure: true   # Allow access to the dashboard without authentication (for development)<\/mark>\r\n<\/code><\/pre>\n<p><strong>Note:<\/strong> Allowing access to the Traefik dashboard without authentication poses a security risk, as it can expose sensitive configuration details to unauthorized users. Remember to only use this <code>insecure<\/code> option in testing environments.<\/p>\n<p>You can then access the Traefik dashboard on port <code>8080<\/code> :<\/p>\n<pre><code class=\"language-yaml\">http:\/\/your_domain.com:8080\/dashboard\r\n<\/code><\/pre>\n<p>In this dashboard, you can monitor and manage Traefik's routing, view active services, routers, middlewares, and review logs for troubleshooting.<\/p>\n<h3>Step 4: Access Traefik Logs<\/h3>\n<p>If you still can't access the dashboard, check the logs for errors:<\/p>\n<pre><code class=\"language-yaml\">$ docker compose logs reverse-proxy\r\n<\/code><\/pre>\n<h3>Step 5: Set up Traefik to Redirect HTTP to HTTPS<\/h3>\n<p>To redirect HTTP to HTTPS with Traefik, you need to add a middleware for HTTP to HTTPS redirection and apply it to the <code>web<\/code> entrypoint. Open <code>traefik.yml<\/code> and add the following highlighted parts:<\/p>\n<pre><code class=\"language-yaml\">log:\r\n  level: \"DEBUG\"  # Set log level to DEBUG for detailed logs\r\nentryPoints:\r\n  web:\r\n    address: \":80\"\r\n    <mark>http:\r\n      redirections:\r\n        entryPoint:\r\n          to: websecure\r\n          scheme: https<\/mark>\r\n  websecure:\r\n    address: \":443\"\r\n  traefik:\r\n    address: \":8080\"  # Dashboard entry point\r\ncertificatesResolvers:\r\n  myresolver:\r\n    acme:\r\n      email: your_email@example.com\r\n      storage: acme.json\r\n      httpChallenge:\r\n        entryPoint: web\r\nproviders:\r\n  docker:\r\n    exposedByDefault: false\r\n<\/code><\/pre>\n<p>With these changes, all HTTP traffic will be automatically redirected to HTTPS. Here's a breakdown of what happens:<\/p>\n<ol>\n<li>When a user accesses your site via HTTP (port 80), they hit the <code>web<\/code> entrypoint.<\/li>\n<li>The <code>web<\/code> entrypoint is configured to redirect all traffic to the <code>websecure<\/code> entrypoint using HTTPS.<\/li>\n<li>The <code>websecure<\/code> entrypoint handles the HTTPS traffic on port 443.<\/li>\n<\/ol>\n<p>Your services (apache and nginx) are already configured to use both <code>web<\/code> and <code>websecure<\/code> entrypoints, so they will work correctly with this setup.<\/p>\n<p>Remember to restart your Traefik container after making these changes:<\/p>\n<pre><code>$ docker-compose down\r\n$ docker-compose up -d\r\n<\/code><\/pre>\n<p>This Traefik configuration will ensure that all HTTP traffic is redirected to HTTPS, improving the security of your web services.<!-- notionvc: ec352a1a-367c-464e-9d3d-76f85f4fe918 --><\/p>\n<h3>Step 6: Using Traefik\u2019s PathPrefix<\/h3>\n<p>Traefik's PathPrefix router rule feature allows you to route traffic based on URL paths. This is particularly useful when you want to direct requests to different services based on the URL path.<\/p>\n<p>For example, you can set up requests to the <code>\/app1<\/code> URL to be served by Apache, and <code>\/app2<\/code> to be served by Nginx.<\/p>\n<p>Here's an example of how to use PathPrefix with Traefik:<\/p>\n<pre><code class=\"language-yaml\">version: '3'\r\nservices:\r\n  reverse-proxy:\r\n    image: traefik:latest\r\n    command: --configFile=\/etc\/traefik\/traefik.yml\r\n    ports:\r\n      - \"80:80\"       # HTTP\r\n      - \"443:443\"     # HTTPS\r\n      - \"8080:8080\"   # Traefik dashboard\r\n    volumes:\r\n      - \/var\/run\/docker.sock:\/var\/run\/docker.sock\r\n      - .\/traefik.yml:\/etc\/traefik\/traefik.yml\r\n      - .\/acme.json:\/acme.json\r\n    networks:\r\n      - traefik\r\n\r\n  apache:\r\n    image: httpd:latest\r\n    labels:\r\n      - \"traefik.enable=true\"\r\n      <mark>- \"traefik.http.routers.apache.rule=Host(`example.com`) &amp;&amp; PathPrefix(`\/app1`)\"<\/mark>\r\n      - \"traefik.http.routers.apache.entrypoints=web,websecure\"\r\n      - \"traefik.http.routers.apache.tls.certresolver=myresolver\"\r\n      - \"traefik.http.services.apache.loadbalancer.server.port=80\"\r\n    networks:\r\n      - traefik\r\n\r\n  nginx:\r\n    image: nginx:latest\r\n    labels:\r\n      - \"traefik.enable=true\"\r\n      <mark>- \"traefik.http.routers.nginx.rule=Host(`example.com`) &amp;&amp; PathPrefix(`\/app2`)\"<\/mark>\r\n      - \"traefik.http.routers.nginx.entrypoints=web,websecure\"\r\n      - \"traefik.http.routers.nginx.tls.certresolver=myresolver\"\r\n      - \"traefik.http.services.nginx.loadbalancer.server.port=80\"\r\n    networks:\r\n      - traefik\r\n\r\nnetworks:\r\n  traefik:\r\n    external: true\r\n<\/code><\/pre>\n<p>In this updated configuration:<\/p>\n<ol>\n<li>The Apache service will handle requests to <code>https:\/\/example.com\/app1<\/code> and any subpaths (e.g., <code>https:\/\/example.com\/app1\/users<\/code>, <code>https:\/\/example.com\/app1\/products<\/code>, etc.).<\/li>\n<li>The Nginx service will handle requests to <code>https:\/\/example.com\/app2<\/code> and any subpaths.<\/li>\n<\/ol>\n<p>The key changes are in the <code>traefik.http.routers.[service].rule<\/code> labels:<\/p>\n<ul>\n<li>For Apache: <code>Host(`<\/code><code>example.com) &amp;&amp; PathPrefix(`\/app1`<\/code><code>)<\/code><\/li>\n<li>For Nginx: <code>Host(`<\/code><code>example.com`)<\/code><code> &amp;&amp; PathPrefix(`\/app2`<\/code><code>)<\/code><\/li>\n<\/ul>\n<p>These rules combine the <code>Host<\/code> matcher with the <code>PathPrefix<\/code> matcher using the <code>&amp;&amp;<\/code> (AND) operator. This means the rule will only match if both conditions are true.<\/p>\n<p>A few important notes:<\/p>\n<ol>\n<li>Make sure to replace <code>example.com<\/code> with your actual domain name.<\/li>\n<li>The <code>PathPrefix<\/code> rule will match any path that starts with the specified prefix. For example, <code>\/app1<\/code> will match <code>\/app1<\/code>, <code>\/app1\/<\/code>, <code>\/app1\/users<\/code>, etc.<\/li>\n<li>If you want to strip the prefix before forwarding the request to your service, you can add a middleware:\n<pre><code class=\"language-yaml\">- \"traefik.http.middlewares.strip-app1.stripprefix.prefixes=\/app1\"\r\n- \"traefik.http.routers.apache.middlewares=strip-app1\"\r\n<\/code><\/pre>\n<p>This would remove <code>\/app1<\/code> from the path before sending the request to the Apache service.<\/li>\n<li>If your services are serving content from subdirectories (e.g., Apache serving from <code>\/usr\/local\/apache2\/htdocs\/app1<\/code>), you might not need to strip the prefix.<\/li>\n<\/ol>\n<p>Remember to restart your Docker containers after making these changes:<\/p>\n<pre><code class=\"language-bash\">$ docker-compose down\r\n$ docker-compose up -d\r\n<\/code><\/pre>\n<p>This configuration allows you to host multiple applications or services on the same domain, differentiated by their URL paths.<\/p>\n<p><!-- notionvc: df55cd3d-6fcb-4af7-9aba-7235343891ff --><\/p>\n<h2>Conclusion<\/h2>\n<p>With this, you\u2019re now up and running with a proxied, load-balanced, fully Dockerized reverse proxy that\u2019s fully HTTPS-enabled.<\/p>\n<p><strong><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-1553 size-full\" src=\"https:\/\/www.ssdnodes.com\/wp-content\/uploads\/2018\/05\/l0MYt5jPR6QX5pnqM.gif\" alt=\"Traefik successfully installed\" width=\"370\" height=\"208\" \/><\/strong><\/p>\n<h2><a id=\"Conclusion_and_moving_forward_with_Traefik_325\"><\/a>You installed Traefik, so now what?<\/h2>\n<p>Now that you have installed Traefik and run it from both the binary and using docker-compose, you\u2019re ready to add more microservices! If you add new Docker images in the <code>docker-compose.yml<\/code>, Traefik will recognize newly added backends immediately and route the request to it without any further configuration of Traefik or restarting it.<\/p>\n<p>For more configuration options, see the <a href=\"https:\/\/docs.traefik.io\/#the-trfik-quickstart-using-docker\" target=\"_blank\" rel=\"noopener\">Traefik documentation<\/a>.<\/p>\n<p>Now, you might be asking, \u201cWhat should I install <em>behind<\/em> this amazing Traefik reverse proxy?\u201d<\/p>\n<p>Well, how about you start with <a href=\"https:\/\/www.ssdnodes.com\/blog\/installing-nextcloud-docker\/\">self-hosting NextCloud<\/a>?<\/p>\n<p>The options are endless\u2014have fun and get more from your <a href=\"https:\/\/ssdnodes.com\/\" target=\"_blank\" rel=\"noopener\">VPS<\/a> at the same time!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Want an easy way to deploy multiple Dockerized apps, complete with HTTPS, on a single VPS? Save headaches and deploy fast with Traefik, the do-all reverse proxy.<\/p>\n","protected":false},"author":19,"featured_media":10968,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[18,30],"tags":[245,205],"class_list":["post-1552","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","category-tutorials","tag-traefik","tag-vps"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts\/1552","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/users\/19"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/comments?post=1552"}],"version-history":[{"count":30,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts\/1552\/revisions"}],"predecessor-version":[{"id":12923,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/posts\/1552\/revisions\/12923"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/media\/10968"}],"wp:attachment":[{"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/media?parent=1552"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/categories?post=1552"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ssdnodes.com\/wp-json\/wp\/v2\/tags?post=1552"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}