Skip to content
Stand with Ukraine flag

Cluster setup using Docker Compose

This guide walks you through setting up ThingsBoard Professional Edition in cluster mode using Docker Compose with microservices architecture. Docker container images are available on Docker Hub.

For a simpler single-node installation, see Docker (Linux, macOS).

Install Docker:

A server with at least 8 GB of RAM (16 GB recommended for production cluster deployments).

Terminal window
docker pull thingsboard/tb-pe-node:4.3.1.4PE
docker pull thingsboard/tb-pe-web-report:4.3.1.4PE
docker pull thingsboard/tb-pe-web-ui:4.3.1.4PE
docker pull thingsboard/tb-pe-js-executor:4.3.1.4PE
docker pull thingsboard/tb-pe-http-transport:4.3.1.4PE
docker pull thingsboard/tb-pe-mqtt-transport:4.3.1.4PE
docker pull thingsboard/tb-pe-coap-transport:4.3.1.4PE
docker pull thingsboard/tb-pe-lwm2m-transport:4.3.1.4PE
docker pull thingsboard/tb-pe-snmp-transport:4.3.1.4PE

Step 2. Clone ThingsBoard PE Docker Compose scripts

Section titled “Step 2. Clone ThingsBoard PE Docker Compose scripts”
Terminal window
git clone -b release-4.3.1.4 https://github.com/thingsboard/thingsboard-pe-docker-compose.git tb-pe-docker-compose --depth 1
cd tb-pe-docker-compose

Step 3. Obtain and configure the license key

Section titled “Step 3. Obtain and configure the license key”

We assume you have already chosen your subscription plan or decided to purchase a perpetual license. If not, navigate to the pricing page to select the best license option for your case. See How to get a pay-as-you-go subscription or How to get a perpetual license for details.

Edit the ThingsBoard node environment file:

Terminal window
nano tb-node.env

Replace PUT_YOUR_LICENSE_SECRET_HERE with your actual license secret:

Terminal window
TB_LICENSE_SECRET=PUT_YOUR_LICENSE_SECRET_HERE

The docker compose scripts support three deployment modes. Edit the .env file:

Terminal window
nano .env

Set the TB_SETUP variable to one of the following:

ModeDescription
basic (recommended, default)ThingsBoard Core and Rule Engine run in one JVM (requires 1 license). MQTT, CoAP, and HTTP transports run in separate containers.
monolithThingsBoard Core, Rule Engine, and all transports run in one JVM (requires 1 license). Minimizes memory footprint.
advancedThingsBoard Core and Rule Engine run in separate replicated containers (requires 4 licenses).

All deployment modes support separate JS executors, Redis, and different queue services.

Edit the .env file to set the database type:

Terminal window
nano .env

Set the DATABASE variable to one of:

ValueDescription
postgresUse PostgreSQL for all data
hybridUse PostgreSQL for entities and Cassandra for time-series data

ThingsBoard cluster deployments require an external message broker. In Memory queue is not suitable for cluster mode.

  • Kafka — recommended for production. Used on most ThingsBoard production environments. Works for on-prem and private cloud deployments.
  • Confluent Cloud — fully managed streaming platform based on Kafka. Useful for cloud-agnostic deployments.

Apache Kafka is an open-source stream-processing platform.

Edit the .env file:

Terminal window
nano .env

Verify the following line:

Terminal window
TB_QUEUE_TYPE=kafka

Edit the .env file:

Terminal window
nano .env

Set MONITORING_ENABLED to true:

Terminal window
MONITORING_ENABLED=true

After deployment, Prometheus will be available at http://localhost:9090 and Grafana at http://localhost:3000 (default login: admin / foobar).

Step 8. Enable Trendz Analytics (optional)

Section titled “Step 8. Enable Trendz Analytics (optional)”

You may optionally install Trendz Analytics at any time.

Edit the .env file:

Terminal window
nano .env

Set TRENDZ_ENABLED to true:

Terminal window
TRENDZ_ENABLED=true

Create log folders for the services. The script requires sudo permissions to change ownership:

Terminal window
./docker-create-log-folders.sh

Verify that all required volume folders are available and have correct ownership:

Terminal window
./docker-check-log-folders.sh
Terminal window
./docker-install-tb.sh --loadDemo

The --loadDemo flag loads sample tenant account, dashboards, and devices for evaluation and testing.

Terminal window
./docker-start-services.sh

After a while when all services are started, open http://localhost in your browser. You should see the ThingsBoard login page. Use the following default credentials:

You can change passwords for each account in the account profile page.

See Getting Started for your next steps after login.

Stream ThingsBoard node logs:

Terminal window
docker compose -f $TB_SETUP/docker-compose.yml logs -f tb-core1 tb-rule-engine1

View the state of all containers:

Terminal window
docker compose -f $TB_SETUP/docker-compose.yml ps

Stream logs of all services:

Terminal window
docker compose -f $TB_SETUP/docker-compose.yml logs -f

Stop all services:

Terminal window
./docker-stop-services.sh

Remove all deployed containers:

Terminal window
./docker-remove-services.sh

Update specific services (pull newer image and rebuild container):

Terminal window
./docker-update-service.sh [SERVICE...]

If [SERVICE...] is omitted, all services are updated.

The deployment uses HAProxy for proxying traffic to containers. By default ports 80 and 443 are used. To use HTTPS with a valid certificate:

Terminal window
docker exec haproxy-certbot certbot-certonly --domain your_domain --email your_email
docker exec haproxy-certbot haproxy-refresh

When a new ThingsBoard release becomes available, update your installation to benefit from the latest features and security patches.

See the Upgrade Instructions for detailed steps.

Trendz Analytics has a different version system and should be updated separately from the ThingsBoard platform.

Edit the .env file and set TRENDZ_VERSION to the target version, then run:

Terminal window
./docker-stop-services.sh
./docker-upgrade-trendz.sh
./docker-start-services.sh

If you observe errors related to DNS issues, for example:

Terminal window
127.0.1.1:53: cannot unmarshal DNS message

Configure your system to use Google public DNS servers. See Linux and macOS instructions.

Connecting to PostgreSQL on the Docker host

Section titled “Connecting to PostgreSQL on the Docker host”

Inside a container, localhost and 127.0.0.1 point to the container itself, not to the Docker host. A ThingsBoard container reaches a PostgreSQL instance installed on the host through a different address.

Set the database address

The value of SPRING_DATASOURCE_URL depends on where PostgreSQL runs:

PostgreSQL locationSPRING_DATASOURCE_URL
Service in the same compose filejdbc:postgresql://postgres:5432/thingsboard
Docker hostjdbc:postgresql://host.docker.internal:5432/thingsboard
Another serverjdbc:postgresql://SERVER_IP:5432/thingsboard

On macOS, Docker Desktop resolves host.docker.internal to the host automatically. On Linux, map the alias to the host gateway in every ThingsBoard service that connects to the database:

services:
tb-core1:
extra_hosts:
- "host.docker.internal:host-gateway"

Allow the Docker subnet in PostgreSQL

A PostgreSQL instance running on the host accepts local connections only until you configure it otherwise. Find the subnet of your Docker network first:

Terminal window
docker network ls
docker network inspect NETWORK_NAME --format '{{(index .IPAM.Config 0).Subnet}}'

Set the listen address in postgresql.conf:

listen_addresses = '*'

Add a matching client entry to pg_hba.conf. The database and user must match SPRING_DATASOURCE_URL and SPRING_DATASOURCE_USERNAME, and the subnet must be the one you found. The authentication method must match how the password is stored, so use md5 instead of scram-sha-256 on instances that still store MD5 passwords:

host thingsboard DB_USER 172.18.0.0/16 scram-sha-256

Restart PostgreSQL. A reload is enough for pg_hba.conf, but listen_addresses is applied at server start only:

Terminal window
sudo systemctl restart postgresql

Verify the connection

Run psql from a temporary container. It takes the same network path as ThingsBoard, which separates a networking problem from a ThingsBoard configuration problem. Replace DB_USER and DB_PASSWORD with the values from SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD:

Terminal window
docker run --rm --add-host=host.docker.internal:host-gateway postgres:18 \
psql "postgresql://DB_USER:DB_PASSWORD@host.docker.internal:5432/thingsboard" -c "SELECT 1;"

If this command succeeds and ThingsBoard still fails, the network path is fine and the problem is in the ThingsBoard configuration.

Check for a host firewall

Docker maps its internal networks to the host with iptables rules. Additional firewall software can interfere with those rules and drop the traffic before it reaches PostgreSQL. If connections time out instead of being rejected, check whether a firewall like UFW or firewalld is installed and enabled on the host, and whether its configuration blocks traffic coming from the Docker networks.