Skip to content

Running Multiple Instances on a Single Host

It is possible to run multiple Bergwerk instances on a single host or virtual machine.
However, this setup is not supported out of the box and requires some manual adjustments to the configuration files — primarily the docker-compose.yaml and Caddyfile files.

This section will guide you step-by-step through an example setup with two independent Bergwerk instances, bot1 and bot2, running on the same host system.


Example: Two Bergwerk Instances

First, clone the Bergwerk repository twice into separate directories:

git clone https://github.com/HTW-Berlin-KI-Werkstatt/bergwerk bot1
git clone https://github.com/HTW-Berlin-KI-Werkstatt/bergwerk bot2

This will create two directories — bot1 and bot2 — each containing its own copy of the Bergwerk source files.


Step 1: Adjust the Docker Compose Configuration

Each Bergwerk instance comes with its own docker-compose.yaml.
We need to modify the Caddy service in both files to avoid port conflicts and allow proper network aliasing.

Example: bot1/docker-compose.yaml

Locate the caddy section in the file and replace it with the following:

  caddy:
    image: caddy:latest
    env_file:
      - config.env
    restart: always
    volumes:
      - ./bergwerk-caddy/Caddyfile:/etc/caddy/Caddyfile
      - ./bergwerk-caddy/html:/var/www/html
      - ./persist/caddy_data:/data
      - ./persist/caddy_config:/config
    networks:
      netzwerk:
        aliases:
          - bot1_caddy

Example: bot2/docker-compose.yaml

Do the same in the bot2 directory, changing the alias to bot2_caddy:

  caddy:
    image: caddy:latest
    env_file:
      - config.env
    restart: always
    volumes:
      - ./bergwerk-caddy/Caddyfile:/etc/caddy/Caddyfile
      - ./bergwerk-caddy/html:/var/www/html
      - ./persist/caddy_data:/data
      - ./persist/caddy_config:/config
    networks:
      netzwerk:
        aliases:
          - bot2_caddy

Each Caddy container now operates in its own Docker network, without port conflicts.


Step 2: Update Each Caddyfile

Next, adjust both Caddyfile configurations (bot1/bergwerk-caddy/Caddyfile and bot2/bergwerk-caddy/Caddyfile).

The default configuration typically starts with something like:

{$SERVER} {

    root * /var/www/html
    file_server

    handle_path /wiki* {
        reverse_proxy wiki:80
    }

    handle /admin* {
        reverse_proxy admin:80 {
            header_up X-Forwarded-Prefix /admin
        }
    }

    handle /socket.io/* {
        reverse_proxy socketio:5005
    }

    handle_errors {
        @404 {
            expression {http.error.status_code} == 404
        }
        rewrite @404 /404.html
        file_server
    }
}

Change the first line of each file to listen only on port 80, instead of a variable or HTTPS binding:

:80 {

Step 3: Configure Environment Variables

Each instance requires its own config.env file with unique credentials and server URLs.

Example: bot1/config.env

MEDIAWIKI_ADMIN=admin
MEDIAWIKI_ADMIN_PASSWORD=secret

BOT_USERNAME=bot
BOT_PASSWORD=secret

SQL_USERNAME=dbuser
SQL_PASSWORD=secret

SERVER=https://bot1.example.com

Example: bot2/config.env

MEDIAWIKI_ADMIN=admin
MEDIAWIKI_ADMIN_PASSWORD=secret

BOT_USERNAME=bot
BOT_PASSWORD=secret

SQL_USERNAME=dbuser
SQL_PASSWORD=secret

SERVER=https://bot2.example.com

Make sure that: - Each domain (bot1.example.com and bot2.example.com) points to the same host IP address. - Passwords are strong and unique. - The SERVER variable reflects the intended hostname for each instance.


Step 4: Add an Edge Caddy Server

To handle inbound HTTPS traffic and route it to the correct bot based on hostname, create a third Caddy instance — an edge proxy.

Create a new directory caddy.edge and add the following two files.

docker-compose.yaml

version: "3.9"

services:
  caddy-edge:
    image: caddy:latest
    restart: always
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile.edge:/etc/caddy/Caddyfile
      - ./persist/caddy_data:/data
      - ./persist/caddy_config:/config
    networks:
      - bot1_netzwerk
      - bot2_netzwerk

networks:
  bot1_netzwerk:
    external: true
  bot2_netzwerk:
    external: true

Caddyfile.edge

https://bot1.example.com {
    reverse_proxy bot1_caddy:80
}

https://bot2.example.com {
    reverse_proxy bot2_caddy:80
}

This edge server terminates HTTPS connections and forwards traffic to the correct backend instance (bot1 or bot2) using the host header.


Step 5: Starting the Instances

Once all configurations are in place, start each instance sequentially:

cd bot1
docker compose -p bot1 up -d

cd ../bot2
docker compose -p bot2 up -d

cd ../caddy.edge
docker compose up -d

You should now be able to access both chatbots:


Summary

You have successfully configured two independent Bergwerk instances on a single host using Docker Compose and Caddy.
The edge Caddy server acts as the secure entry point, routing incoming HTTPS traffic to the appropriate backend container based on the domain name.

This approach can be extended to additional instances as needed — just repeat the same pattern with unique directories, ports, and network aliases.