Skip to content
© 2026 The ThingsBoard Authors
Try for free

ThingsBoard Cloud

Choose your data region

Your data stays in the region you choose, for residency and compliance. No credit card required.

Rather run it yourself? Install on your own servers

Cluster setup using Docker Compose

This guide walks you through setting up ThingsBoard in cluster mode using Docker Compose with microservices architecture. Licensing is free and requires no credit card. 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).

You’ll also need outbound internet access to pull Docker images and to reach the ThingsBoard License Portal during activation.

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

Step 2. Clone ThingsBoard Docker Compose Scripts

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

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:

Mode Description
basic (recommended, default) ThingsBoard Core and Rule Engine run in one JVM (requires 1 license). MQTT, CoAP, and HTTP transports run in separate containers.
monolith ThingsBoard Core, Rule Engine, and all transports run in one JVM (requires 1 license). Minimizes memory footprint.
advanced ThingsBoard Core and Rule Engine run in separate replicated containers (requires a license for 4 deployments).

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:

Value Description
postgres Use PostgreSQL for all data
hybrid Use 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 7. Enable Trendz Analytics (Optional)

Section titled “Step 7. 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
Terminal window
./docker-start-services.sh

After a while when all services are started, open ThingsBoard in a web browser:

http://localhost

On first launch you are greeted with the activation screen:

Welcome to ThingsBoard 4.4.0
Get your free license and start building

Continue with the next step to license and activate your instance.

Step 9. License and Activate Your Instance

Section titled “Step 9. License and Activate Your Instance”

Opening ThingsBoard in your browser for the first time shows an activation welcome screen.

  1. Click Open the License Portal, then create an account or sign in.
  2. Choose a free license: Commercial (up to 100 devices, one server) or Non-commercial (up to 1,000 devices, any number of servers).
  3. Check the confirmation box to agree to the Terms of Use, Privacy Policy, and ThingsBoard License (BUSL 1.1), then click Accept and activate to issue the license and activate your instance.
  4. Click Continue setup on your instance to proceed to account creation. Your license key stays available on this screen and in your License Portal account.

Step 10. Create Your Administrator Account

Section titled “Step 10. Create Your Administrator Account”

Once activated, ThingsBoard prompts you to create your System Administrator account — the account that manages the platform itself (tenants, system settings, platform-wide resources).

  1. Enter Email, Password, and Confirm password.
  2. The Set up a demo tenant option is selected by default: it creates a ready-made tenant with dashboards, devices, and rule chains for exploring the platform before building your own solution. Clear it if you want to start with an empty platform.
  3. Click Create account. You are signed in as the system administrator.

Your ThingsBoard instance is now installed and running.

Serving ThingsBoard over HTTPS encrypts the traffic between browsers and the server and prevents browser security warnings. HTTPS is handled by HAProxy: it accepts incoming traffic on ports 80 (HTTP) and 443 (HTTPS), terminates TLS with a trusted certificate from Let’s Encrypt, and forwards requests to ThingsBoard.

Before you start, make sure that:

  • a domain name is assigned to your server, and its DNS record points to the server’s IP address;
  • ports 80 and 443 are reachable from the internet.

The deployment already includes HAProxy as the haproxy-certbot container, so you only need to request the certificate. Replace YOUR_DOMAIN and YOUR_EMAIL with your values, then request the certificate and reload HAProxy to apply it:

Terminal window
docker exec haproxy-certbot certbot-certonly --domain YOUR_DOMAIN --email YOUR_EMAIL
docker exec haproxy-certbot haproxy-refresh

Run these commands from the repository root. Pick the tab that matches the TB_SETUP value in your .env file:

Stream ThingsBoard node logs:

Terminal window
docker compose --env-file .env -f basic/docker-compose.yml logs -f tb-monolith | grep --line-buffered --color=always -E 'Started ThingsboardServerApplication|$'

View the state of all containers:

Terminal window
docker compose --env-file .env -f basic/docker-compose.yml ps

Stream logs of all services:

Terminal window
docker compose --env-file .env -f basic/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.

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 location SPRING_DATASOURCE_URL
Service in the same compose file jdbc:postgresql://postgres:5432/thingsboard
Docker host jdbc:postgresql://host.docker.internal:5432/thingsboard
Another server jdbc: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.

With ThingsBoard running, these concept guides help you build your first solution: