Load Balancing in Docker Compose with Caddy

In my previous article, I wrote about using NGINX as a load balancer in Docker Compose. This has some warts and going forward I would recommend using Caddy. It has active load balancing capabilities baked in and a simple configuration file.

Caddy Load Balancer in Docker Compose

We are going to utilize our previous setup for testing. I will instead be using Caddy as the load balancer. I will continue to use server containers that will print out the hostname of the current container along with the request details.

One of the benefits of Caddy is the dead simple config file. Below is the config for this setup.

:80 {

    encode zstd gzip

    reverse_proxy www01:8080 www02:8080 {

        health_uri /
        health_interval 5s
        health_timeout 3s
        health_status 200


The two workloads will run on port 8080 and the Caddy load balancer will be exposed to our local machine on port 80. We will isolate these containers in a network called example.

version: "3.9"
      - example
    image: caddy:2-alpine
      - ./caddy/data:/data
      - ./caddy/config/Caddyfile:/etc/caddy/Caddyfile
      - www01
      - www02
      - "80:80"
    image: jmalloc/echo-server
    hostname: www01
      - example
      - "8080"
    image: jmalloc/echo-server
    hostname: www02
      - example
      - "8080"


Lets run this example.

docker-compose up --build --remove-orphans

Then try to hit localhost in your browser of choice.

Try refreshing a few times and you will see the request is served by a different container as it switches between the upstream destinations. Now lets try killing one of the containers.

docker kill $ID

Replace $ID with one of the ID's from the browser.

Try refreshing a few more times and you will see Caddy no longer serves traffic from that container.

Example Project

You can download the files for this example project here.