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).
Prerequisites
Section titled “Prerequisites”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.
Step 1. Pull ThingsBoard Images
Section titled “Step 1. Pull ThingsBoard Images”docker pull thingsboard/tb-node:4.4.0docker pull thingsboard/tb-web-report:4.4.0docker pull thingsboard/tb-web-ui:4.4.0docker pull thingsboard/tb-js-executor:4.4.0docker pull thingsboard/tb-http-transport:4.4.0docker pull thingsboard/tb-mqtt-transport:4.4.0docker pull thingsboard/tb-coap-transport:4.4.0docker pull thingsboard/tb-lwm2m-transport:4.4.0docker pull thingsboard/tb-snmp-transport:4.4.0docker pull thingsboard/tb-integration-executor:4.4.0Step 2. Clone ThingsBoard Docker Compose Scripts
Section titled “Step 2. Clone ThingsBoard Docker Compose Scripts”git clone -b release-4.4 https://github.com/thingsboard/thingsboard-pe-docker-compose.git tb-pe-docker-compose --depth 1cd tb-pe-docker-composeStep 3. Configure Deployment Type
Section titled “Step 3. Configure Deployment Type”The docker compose scripts support three deployment modes. Edit the .env file:
nano .envSet 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.
Step 4. Configure Database
Section titled “Step 4. Configure Database”Edit the .env file to set the database type:
nano .envSet 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 |
Step 5. Choose Queue Service
Section titled “Step 5. Choose Queue Service”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:
nano .envVerify the following line:
TB_QUEUE_TYPE=kafkaTo use Confluent Cloud, first create an account, then create a Kafka cluster and obtain your API Key.
Edit the .env file:
nano .envSet the queue type:
TB_QUEUE_TYPE=confluentConfigure the Confluent Cloud environment file. Replace CLUSTER_API_KEY, CLUSTER_API_SECRET, and confluent.cloud:9092 with your actual values:
nano queue-confluent-cloud.envTB_QUEUE_TYPE=kafka
TB_KAFKA_SERVERS=confluent.cloud:9092TB_QUEUE_KAFKA_REPLICATION_FACTOR=3
TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD=trueTB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM=httpsTB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM=PLAINTB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG='org.apache.kafka.common.security.plain.PlainLoginModule required username="CLUSTER_API_KEY" password="CLUSTER_API_SECRET";'TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL=SASL_SSLTB_QUEUE_KAFKA_CONFLUENT_USERNAME=CLUSTER_API_KEYTB_QUEUE_KAFKA_CONFLUENT_PASSWORD=CLUSTER_API_SECRET
TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:104857600
TB_QUEUE_CORE_POLL_INTERVAL_MS=1000TB_QUEUE_CORE_PARTITIONS=2TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS=1000TB_QUEUE_TRANSPORT_REQUEST_POLL_INTERVAL_MS=1000TB_QUEUE_TRANSPORT_RESPONSE_POLL_INTERVAL_MS=1000TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS=1000TB_QUEUE_VC_INTERVAL_MS=1000TB_QUEUE_VC_PARTITIONS=1You can update the default Rule Engine queue configuration using the UI. See Rule Engine Queues for details.
Step 6. Enable Monitoring (Optional)
Section titled “Step 6. Enable Monitoring (Optional)”Edit the .env file:
nano .envSet MONITORING_ENABLED to true:
MONITORING_ENABLED=trueAfter 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:
nano .envSet TRENDZ_ENABLED to true:
TRENDZ_ENABLED=trueStep 8. Install and Start ThingsBoard
Section titled “Step 8. Install and Start ThingsBoard”Create Host Volumes
Section titled “Create Host Volumes”Create log folders for the services. The script requires sudo permissions to change ownership:
./docker-create-log-folders.shVerify that all required volume folders are available and have correct ownership:
./docker-check-log-folders.shRun Installation
Section titled “Run Installation”./docker-install-tb.shStart Services
Section titled “Start Services”./docker-start-services.shAccess ThingsBoard Web UI
Section titled “Access ThingsBoard Web UI”After a while when all services are started, open ThingsBoard in a web browser:
http://localhostOn first launch you are greeted with the activation screen:
Welcome to ThingsBoard 4.4.0Get your free license and start buildingContinue 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.
- Click Open the License Portal, then create an account or sign in.
- Choose a free license: Commercial (up to 100 devices, one server) or Non-commercial (up to 1,000 devices, any number of servers).
- 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.
- 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.
- Click Already have a license?, paste your license key, and click Activate.
- Your instance is now activated. The license is saved on this server 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).
- Enter Email, Password, and Confirm password.
- 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.
- Click Create account. You are signed in as the system administrator.
Your ThingsBoard instance is now installed and running.
[Optional] Configure HTTPS
Section titled “[Optional] Configure HTTPS”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:
docker exec haproxy-certbot certbot-certonly --domain YOUR_DOMAIN --email YOUR_EMAILdocker exec haproxy-certbot haproxy-refreshInspect Logs and Control Containers
Section titled “Inspect Logs and Control Containers”Run these commands from the repository root. Pick the tab that matches the TB_SETUP value in your .env file:
Stream ThingsBoard node logs:
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:
docker compose --env-file .env -f basic/docker-compose.yml psStream logs of all services:
docker compose --env-file .env -f basic/docker-compose.yml logs -fStream ThingsBoard node logs:
docker compose --env-file .env -f monolith/docker-compose.yml logs -f tb-monolith | grep --line-buffered --color=always -E 'Started ThingsboardServerApplication|$'View the state of all containers:
docker compose --env-file .env -f monolith/docker-compose.yml psStream logs of all services:
docker compose --env-file .env -f monolith/docker-compose.yml logs -fStream ThingsBoard node logs:
docker compose --env-file .env -f advanced/docker-compose.yml logs -f tb-core1 tb-core2 tb-rule-engine1 tb-rule-engine2View the state of all containers:
docker compose --env-file .env -f advanced/docker-compose.yml psStream logs of all services:
docker compose --env-file .env -f advanced/docker-compose.yml logs -fStop all services:
./docker-stop-services.shRemove all deployed containers:
./docker-remove-services.shUpdate specific services (pull newer image and rebuild container):
./docker-update-service.sh [SERVICE...]If [SERVICE...] is omitted, all services are updated.
Troubleshooting
Section titled “Troubleshooting”DNS Issues
Section titled “DNS Issues”If you observe errors related to DNS issues, for example:
127.0.1.1:53: cannot unmarshal DNS messageConfigure 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:
docker network lsdocker 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-256Restart PostgreSQL. A reload is enough for pg_hba.conf, but listen_addresses is applied at server start only:
sudo systemctl restart postgresqlVerify 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:
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.
Next Steps
Section titled “Next Steps”With ThingsBoard running, these concept guides help you build your first solution:
- Getting Started — a guided walkthrough of the platform after installation.
- Multi-Tenancy & Hierarchy — how tenants, customers, and users are organized.
- Digital Twin Model — how devices and assets are modeled in the platform.
- Data Processing — how the Rule Engine transforms and routes incoming data.
- Alarms & Notifications — how to detect conditions and notify users.
- Data Visualization — how to build dashboards and widgets.
Was this helpful?