Set up Traefik Proxy as a Reverse Proxy for Docker Containers on Ubuntu 24.04

Updated on October 18, 2024
Set up Traefik Proxy as a Reverse Proxy for Docker Containers on Ubuntu 24.04 header image

Introduction

Traefik Proxy is a modern open-source reverse proxy and load balancer for deploying microservices. Traefik Proxy as a reverse proxy uses routing rules to dynamically process TCP, UDP, HTTP, and HTTPS client requests to applications in a containerized environment.

This article explains how to install and set up Traefik proxy as a reverse proxy for Docker containers on Ubuntu. You will access the Traefik web administration dashboard and securely expose containerized applications on your server.

Prerequisites

Before you begin:

Set Up Firewall Rules

The Uncomplicated Firewall (UFW) is available and active on Vultr Ubuntu servers by default. Follow the steps below to create new rules to allow Traefik to route incoming HTTP and HTTPS connection requests to applications on your server.

  1. Allow HTTP connections on port 80.

    console
    $ sudo ufw allow 80/tcp
    
  2. Allow HTTPS connections on port 443.

    console
    $ sudo ufw allow 443/tcp
    
  3. View the UFW status and verify that the new connection rules are active.

    console
    $ sudo ufw status
    

    Output:

    Status: active
    
    To                         Action      From
    --                         ------      ----
    22/tcp                     ALLOW       Anywhere                  
    80/tcp                     ALLOW       Anywhere                  
    443/tcp                    ALLOW       Anywhere                  
    22/tcp (v6)                ALLOW       Anywhere (v6)             
    80/tcp (v6)                ALLOW       Anywhere (v6)             
    443/tcp (v6)               ALLOW       Anywhere (v6)

To ensure seamless SSL certificate management, explore how Traefik cert-manager simplifies the process by automating the issuance and renewal of certificates.

Deploy Traefik Using Docker Compose

Traefik uses Docker labels to automatically discover and route traffic to containerized applications. Docker Compose allows you to define and run multi-container applications with multiple labels to define routing paths with Traefik. Follow the steps below to install Traefik using Docker Compose on your server.

  1. View the active Docker Compose version on your server.

    console
    $ docker compose version
    

    Output:

    Docker Compose version v2.29.7
  2. Create a new docker-compose.yml file.

    console
    $ sudo nano docker-compose.yml
    
  3. Add the following configurations to the file.

    yaml
    services:
      traefik:
        image: "traefik:latest"
        container_name: "traefik"
        command:
          - "--log.level=DEBUG"
          - "--api.insecure=true"
          - "--providers.docker=true"
          - "--entryPoints.web.address=:80"
        ports:
          - "80:80"
          - "8080:8080"
        volumes:
          - "/var/run/docker.sock:/var/run/docker.sock"
    

    Save and close the file.

    The above configuration creates a new containerized application using the Traefik image that accepts incoming traffic on the HTTP port 80 and exposes the web administration dashboard on port 8080. Within the configuration:

    • services: Specifies the services to create with specific configuration options.
      • traefik: Creates a new traefik Docker service.
        • image: Configures the traefik service to pull and run the Traefik container image.
        • container_name: Sets the Traefik container image name to traefik.
        • command: Specifies the command line options to execute in the traefik container image.
          • "--log.level=DEBUG": Enables Traefik to run in debug mode and log all runtime errors.
          • "--api.insecure=true": Enables HTTP connections to the Traefik dashboard.
          • "--providers.docker=true": Enables Traefik to detect and configure routes for Docker containers using labels.
          • "--entryPoints.web.address=:80": Sets the HTTP port 80 as the main entry point to listen for incoming traffic. Traefik requires at least one entry point to define the ports to listen for incoming connection requests.
        • ports: Includes port mappings to the host. The value 80:80 binds the Traefik HTTP port 80 to the host, while 8080:8080 enables access to the Traefik dashboard.
        • volumes: Mounts specific paths to Traefik. The /var/run/docker.sock:/var/run/docker.sock value mounts the Docker socket as a volume to allow Traefik to monitor and manage Docker services.
  4. Start Traefik in detached mode.

    console
    $ docker compose up -d
    
  5. View all running Docker containers and verify that the Traefik container status is up.

    console
    $ docker compose ps
    

    Output:

    NAME      IMAGE            COMMAND                  SERVICE   CREATED         STATUS         PORTS
    traefik   traefik:latest   "/entrypoint.sh --lo…"   traefik   6 seconds ago   Up 6 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp

    The Traefik container is actively running based on the above output.

  6. Access your server's public IP address using a web browser such as Chrome on port 8080.

    http://<server-ip>:8080

    Access the traefik dashboard

  7. Navigate to the Providers section and verify that Docker is available.

    Viewing the docker provider

Configure Traefik Proxy as a Reverse Proxy Using Docker Compose

Traefik is actively running and configured to handle HTTP connection requests on port 80. Follow the steps below to create a new sample web server application using the Apache container image to integrate with Traefik and accept connection requests using a domain.

  1. Open the docker-compose.yml file.

    console
    $ nano docker-compose.yml
    
  2. Add the configurations below to the traefik service. Replace app.example.com with your actual domain.

    yaml
    apache:
       image: "httpd:latest"
       container_name: "apache"
       labels:
         - traefik.enable=true
         - traefik.http.routers.apache.rule=Host(`app.example.com`)
         - traefik.http.routers.apache.entrypoints=web
    

    Save and close the file.

    The above configuration creates a new web server application using the Apache container image and accepts incoming connection requests for the app.example.com domain and the web entry point. Within the configuration:

    • apache: Creates a new apache service.
      • image: "httpd:latest": Deploys the apache service using the Apache httpd container image.
      • labels: Sets the Docker labels to assign the apache service enabling Traefik to dynamically route traffic to the application.
        • traefik.enable=true: Enables Traefik to forward traffic to the apache service.
        • traefik.http.routers.apache.rule=Host(`app.example.com`): Sets the domain Traefik uses to listen for incoming connection requests. Specify apache.localhost instead of apache.rule=Host to use localhost if you don't want to specify a domain.
        • traefik.http.routers.apache.entrypoints=web: Sets the web entry point Traefik uses to route incoming requests to the apache service.

    Your modified docker-compose.yml file should look like the one below.

    yaml
    services:
      traefik:
        image: "traefik:latest"
        container_name: "traefik"
        command:
          - "--log.level=DEBUG"
          - "--api.insecure=true"
          - "--providers.docker=true"
          - "--entryPoints.web.address=:80"
        ports:
          - "80:80"
          - "8080:8080"
        volumes:
          - "/var/run/docker.sock:/var/run/docker.sock"
      apache:
         image: "httpd:latest"
         container_name: "apache"
         labels:
           - traefik.enable=true
           - traefik.http.routers.apache.rule=Host(`app.example.com`)
           - traefik.http.routers.apache.entrypoints=web
    
  3. Start the apache service in detached mode.

    console
    $ docker compose up -d
    

    Output:

    [+] Running 2/2
     ✔ Container traefik  Running                                            0.0s 
     ✔ Container apache   Started                                            0.4s
  4. View all running Docker containers and verify apache container is actively running.

    console
    $ docker compose ps
    

    Output:

    NAME      IMAGE            COMMAND                  SERVICE   CREATED          STATUS          PORTS
    apache    httpd:latest     "httpd-foreground"       apache    2 minutes ago    Up 2 minutes    80/tcp
    traefik   traefik:latest   "/entrypoint.sh --lo…"   traefik   35 minutes ago   Up 34 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp
  5. Access your domain in a new web browser window using HTTP and verify that the Apache default page displays. Replace app.example.com with your actual domain.

    http://app.example.com

    Access the Apache Service Proxied through Traefik

  6. Access your Traefik dashboard, navigate to the HTTP tab, and verify that the apache service route is available.

    http://SERVER-IP:8080

    View the apache service route

Set up Automatic HTTPS Using Traefik

Traefik uses certificate resolvers to generate and renew trusted SSL certificates from an automatic certificate management environment (ACME) provider. Traefik initializes an ACME challenge to validate your domain and store the generated certificates in an acme.json file. Follow the steps below to set up automatic HTTPS using Traefik and use Let's Encrypt as the ACME to generate trusted SSL certificates for your apache service domain.

  1. Back up the original docker-compose.yml file.

    console
    $ mv docker-compose.yml http-docker-compose.yml
    
  2. Create a new docker-compose.yml file.

    console
    $ nano docker-compose.yml
    
  3. Add the following configurations to the file. Replace app.example.com with your domain and hello@example.com with your active email address.

    yaml
    services:
      traefik:
        image: "traefik:latest"
        container_name: "traefik"
        command:
          - "--log.level=DEBUG"
          - "--api.insecure=true"
          - "--providers.docker=true"
          - "--entryPoints.apachesecure.address=:443"
          - "--certificatesResolvers.apacheresolver.acme.tlsChallenge=true"
          - "--certificatesResolvers.apacheresolver.acme.email=hello@example.com"
          - "--certificatesResolvers.apacheresolver.acme.storage=/letsencrypt/acme.json"
        ports:
          - "443:443"
          - "8080:8080"
        volumes:
          - "/var/run/docker.sock:/var/run/docker.sock"
          - "./letsencrypt:/letsencrypt"
    
      apache:
        image: "httpd:latest"
        container_name: "apache"
        labels:
          - traefik.enable=true
          - traefik.http.routers.apache.rule=Host(`app.example.com`)
          - traefik.http.routers.apache.entrypoints=apachesecure
          - traefik.http.routers.apache.tls=true
          - traefik.http.routers.apache.tls.certresolver=apacheresolver
    

    Save and close the file.

    The above configuration enables Traefik to accept only secure HTTPS connection requests using the apachesecure entry point on port 443. Within the traefik service configuration:

    • --entryPoints.apachesecure.address=:443: Enables HTTPS connections on port 443 using the apachesecure entry point.
    • --certificatesResolvers.apacheresolver.acme.tlsChallenge=true: Creates a new apacheresolver certificate resolver and uses the ACME TLS-ALPN-01 challenge as a TLS challenge to generate a new SSL certificate. Traefik uses the Let's Encrypt ACME by default.
    • --certificatesResolvers.apacheresolver.acme.email=hello@example.com: Sets ACME challenge email address .
    • --certificatesResolvers.apacheresolver.acme.storage=/letsencrypt/acme.json: Specifies the path to store the ACME configuration to reuse between container restarts.

    Within the apache service configuration:

    • traefik.http.routers.apache.entrypoints=apachesecure: Creates a new apachesecure entry point to handle connection requests.
    • traefik.http.routers.apache.tls=true: Enables secure TLS connections to the service.
    • traefik.http.routers.apache.tls.certresolver=apacheresolver: Creates a new apacheresolver certificate resolver to generate and manage SSL certificates.
  4. Apply the Docker Compose configuration to modify the traefik and apache service containers.

    console
    $ docker compose up traefik apache -d
    
  5. View all running Docker containers and verify the service status.

    console
    $ docker compose ps
    
  6. Access your domain using HTTPS in a new web browser window. Then, verify the connection is secure and the default web page displays.

    https://app.example.com
  7. Access the Traefik dashboard and verify that the apachesecure entry point is available on port 443.

    SERVER-IP:8080

    View the apachesecure entrypoint in Traefik

  8. Navigate to the HTTP tab and verify TLS is active on the apache service.

    View the secure apache server

  9. Stop the traefik and apache container.

    console
    $ docker stop traefik apache
    

Deploy Traefik Using Docker CLI

You can deploy Traefik using Docker CLI to work as a reverse proxy for new or existing Docker containers. A Traefik YAML configuration includes the Docker labels and request routing rules to forward connection requests. Follow the steps below to deploy Traefik using Docker CLI and deploy a sample container using the Nginx image to route connection requests.

  1. Create a new traefik.yml file.

    console
    $ sudo nano traefik.yml
    
  2. Add the following configurations to the file.

    yaml
    entryPoints:
      web:
        address: ":80" 
    
    api:
      dashboard: true   
      insecure: true    
    
    log:
      level: debug      
    
    providers:
      docker:    
        exposedByDefault: false       
        endpoint: "unix:///var/run/docker.sock"
    

    Save and close the file.

    Within the above configuration:

    • entrypoint: Creates a new web entry point that listens for connections on the HTTP port 80.
    • api: Enables the Traefik dashboard.
    • log: Enables debug level logging to include warning and error logs.
    • providers: Sets Docker as the provider and connects using the Docker socket.
  3. Deploy Traefik as a new Docker container, mount the traefik.yml file, and the Docker socket.

    console
    $ docker run -d -p 8080:8080 -p 80:80 \
      -v /var/run/docker.sock:/var/run/docker.sock \
      -v $PWD/traefik.yml:/traefik.yml \
      traefik:v3.1
    
  4. View all running Docker containers and verify that the new Traefik container is running.

    console
    $ docker ps
    
  5. Deploy a new Nginx container using the web entry point label. Replace app.example.com with your actual domain.

    console
    $ docker run -d \
      --label "traefik.enable=true" \
      --label 'traefik.http.routers.nginx.rule=Host(`app.example.com`)' \
      --label "traefik.http.routers.nginx.entrypoints=web" \
      nginx
    
  6. View the running Docker containers and verify that the Nginx container is running.

    console
    $ docker ps
    

    Output:

    CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                                                          NAMES
    6274442a11a2   nginx          "/docker-entrypoint.…"   6 seconds ago    Up 4 seconds    80/tcp                                                                         serene_haslett
    4c5c3db6e4e4   traefik:v3.1   "/entrypoint.sh trae…"   52 seconds ago   Up 51 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   nice_bose
  7. Access your domain in a new web browser window and verify that the Nginx web page displays.

    http://app.example.com

    Output:

    Welcome to nginx!
  8. Access the Traefik dashboard using your server's public IP address and verify the new web route in the HTTP tab.

    http://SERVER-IP:8080

    View the apache service route

Enable Automatic HTTPS Using Traefik

Traefik supports automatic HTTPS to secure connections to the exposed container applications. Follow the steps below to create a new entry point for the HTTPS port 443 and enable the Let's Encrypt ACME labels to generate SSL certificates.

  1. Back up the traefik.yml file.

    console
    $ mv traefik.yml old-traefik.yml
    
  2. Create the traefik.yml file again.

    console
    $ sudo nano traefik.yml
    
  3. Add the following configurations to the file. Replace hello@example.com with your active email address.

    yaml
    entryPoints:
      websecure:
        address: ":443"
    
    api:
      dashboard: true
      insecure: true
    
    log:
      level: debug
    
    providers:
      docker:
        exposedByDefault: false
        endpoint: "unix:///var/run/docker.sock"
    
    certificatesResolvers:
      nginxresolver:
        acme:
          email: hello@example.com
          storage: /letsencrypt/acme.json
          tlsChallenge: true
    

    Save and close the file.

    Within the above configuration:

    • websecure: Creates a new entry point.
    • nginxresolver: Sets the certificate resolver name to use with Let's Encrypt as the ACME.
    • /letsencrypt/acme.json: Uses the acme.json file in the host data directory or creates the Let's Encrypt directory if unavailable.
  4. Stop the active Traefik container. Replace traefik-container-id with your actual Traefik container ID.

    console
    $ docker stop <traefik-container-id> -f
    
  5. Stop the Nginx container. Replace nginx-container-id with your actual Nginx container ID.

    console
    $ docker stop <nginx-container-id> -f
    
  6. Deploy Traefik, map the HTTPS port 443 to the host, and mount the letsencrypt directory.

    console
    $ docker run -d -p 8080:8080 -p 443:443 \
      -v /var/run/docker.sock:/var/run/docker.sock \
      -v $PWD/traefik.yml:/traefik.yml \
      -v $PWD/letsencrypt:/letsencrypt \
      traefik:v3.1
    
  7. View all running Docker containers and verify that Traefik is running.

    console
    $ docker ps
    
  8. Deploy a new Nginx container using the websecure entry point and the nginxresolver certificate resolver. Replace app.example.com with your actual domain.

    console
    $ docker run -d \
      --label "traefik.enable=true" \
      --label 'traefik.http.routers.nginx.rule=Host(`app.example.com`)' \
      --label "traefik.http.routers.nginx.entrypoints=websecure" \
      --label "traefik.http.routers.nginx.tls.certresolver=nginxresolver" \
      nginx
    
  9. Access your domain in a new web browser window using HTTPS.

    https://app.example.com

    Verify that the default Nginx web page displays.

    Access the Nginx Traefik Service

Conclusion

You have deployed Traefik Proxy using Docker Compose and Docker CLI as a reverse proxy to route traffic to container applications. You set up sample web server containers using the Apache and Nginx images to handle connection requests using Traefik. You can also use Traefik as a load balancer or API gateway to securely expose Docker container applications. For more information and Docker labels, visit the Traefik documentation.