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

Installing ThingsBoard using Docker (Linux, macOS)

This guide covers a single-node ThingsBoard installation using Docker Compose on Linux or macOS. By the end, you will have a licensed, activated ThingsBoard instance — free, no credit card required — with a system administrator account and, optionally, a demo tenant, running on your machine. For cluster setup, see Cluster Setup with Docker Compose.

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

Ensure your server meets the minimum requirements:

Use case CPU RAM Recommended services
Development / PoC 1 core 4 GB ThingsBoard, PostgreSQL
Production (small) 2 cores 8 GB ThingsBoard, PostgreSQL, Kafka
Production (recommended) 4+ cores 16+ GB ThingsBoard, PostgreSQL, Kafka, Cassandra

Install Docker on your server:

Create a dedicated directory for your ThingsBoard installation and navigate to it. All subsequent commands in this guide should be run from this directory.

Terminal window
mkdir -p ~/thingsboard && cd ~/thingsboard

ThingsBoard uses a message queue to route messages between its internal services. Select the option that matches your infrastructure:

  • In Memory (default) — built-in queue, no extra setup required. Suitable for development and PoC. Not recommended for production or multi-node deployments.
  • Kafka — high-throughput, durable queue. Run it yourself or use a managed service such as AWS MSK.
  • Confluent Cloud — fully managed Kafka service. Use this if you want Kafka without managing the infrastructure yourself.

Create the docker-compose.yml file:

Terminal window
nano docker-compose.yml

Paste one of the configurations below, save, and exit. Or use the download button to save the file directly.

services:
postgres:
restart: always
image: "postgres:18"
ports:
- "5432"
environment:
POSTGRES_DB: thingsboard
POSTGRES_PASSWORD: postgres
volumes:
- postgres-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d thingsboard"]
interval: 10s
timeout: 5s

Services started:

  • postgres — PostgreSQL database
  • thingsboard — ThingsBoard application node
  • tb-web-report — reporting component for PDF/PNG dashboard exports
Ports (host:container)
Port mappingDescription
8080:8080Web UI and REST API. The left value is the host port — change it if 8080 is already in use.
1883:1883MQTT — plaintext IoT device connections
8883:8883MQTT over TLS — encrypted IoT device connections
5683:5683/udpCoAP — plaintext IoT protocol
5684:5684/udpCoAP over DTLS — encrypted CoAP
5685:5685/udpLwM2M CoAP — plaintext Lightweight M2M
5686:5686/udpLwM2M CoAP over DTLS — encrypted LwM2M
5687:5687/udpLwM2M — plaintext Lightweight M2M (Bootstrap)
5688:5688/udpLwM2M over DTLS — encrypted Lightweight M2M (Bootstrap)
7070:7070Edge RPC (gRPC) — connections from ThingsBoard Edge nodes
9090:9090Remote Integration Executor (gRPC) — used by external integration services
Environment variables
VariableDescription
TB_SERVICE_IDUnique identifier of the ThingsBoard node. Default: tb-node.
TB_LICENSE_SECRETOptional. Your ThingsBoard license key. Commented out by default. If you already have a key, uncomment the line and replace PUT_YOUR_LICENSE_SECRET_HERE with it during configuration. If you don’t, leave it commented out and activate the instance from the web UI after the first start.
TB_LICENSE_INSTANCE_DATA_FILEPath inside the container where the license instance data is stored. Default: /data/license.data, which is on the tb-license-data volume, so the activation survives container restarts and upgrades.
REPORTS_SERVER_ENDPOINT_URLAddress of the tb-web-report service used for PDF/PNG dashboard exports. Default: http://tb-web-report:8383.
POSTGRES_DBSet on the postgres service. Name of the database created on first start. Default: thingsboard.
POSTGRES_PASSWORDSet on the postgres service. Password for the PostgreSQL postgres user. Must match SPRING_DATASOURCE_PASSWORD. Change the default value in production.
SPRING_DATASOURCE_URLPostgreSQL JDBC connection URL. Specifies the host and database name. Default: jdbc:postgresql://postgres:5432/thingsboard.
SPRING_DATASOURCE_PASSWORDPostgreSQL password ThingsBoard uses to connect. Must match POSTGRES_PASSWORD.
TB_QUEUE_TYPEMessage queue type. Options: in-memory (default, single-node only), kafka, rabbitmq. Not set in the In Memory configuration, which uses the default.
TB_KAFKA_SERVERSKafka bootstrap servers. Required when TB_QUEUE_TYPE=kafka. Set to kafka:9092 in the Kafka configuration (the local kafka service); replace localhost:9092 with your Confluent Cloud bootstrap server in the Confluent Cloud configuration.
TB_QUEUE_KAFKA_, TB_QUEUE_POLL_INTERVAL_MS, TB_QUEUE*_PARTITIONSConfluent Cloud configuration only. Enable Confluent Cloud, pass the SASL credentials (CLUSTER_API_KEY, CLUSTER_API_SECRET), and tune the replication factor, poll intervals and partition counts for a managed cluster.
DEFAULT_TRENDZ_URLTrendz Analytics endpoint — pre-configured for optional Trendz integration. Default: http://trendz:8888.
DEFAULT_TB_URLAddress at which other services, such as Trendz, reach ThingsBoard inside the Compose network. Default: http://thingsboard:8080.
Volumes
VolumeDescription
tb-postgres-dataPersists PostgreSQL data across container restarts and upgrades.
tb-kafka-dataPersists Kafka data. Only present when TB_QUEUE_TYPE=kafka.
tb-license-dataPersists license instance data — prevents license re-activation on each restart.

For the full list of configuration parameters, see the Configuration Reference.

Before starting ThingsBoard, initialize the database schema:

Terminal window
docker compose run --rm -e INSTALL_TB=true thingsboard

The container exits automatically once initialization is complete.

Start all containers:

Terminal window
docker compose up -d

Monitor the startup. The line confirming the platform is ready will be highlighted:

Terminal window
docker compose logs -f thingsboard | grep --line-buffered --color=always -E 'Started ThingsboardServerApplication|$'

Press Ctrl+C to detach from the log stream — containers will continue running in the background.

Open ThingsBoard in a web browser:

http://localhost:8080

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 4. License and Activate Your Instance

Section titled “Step 4. 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.

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.

You may optionally install Trendz Analytics at any time. The Trendz compose file extends the main docker-compose.yml — always run them together.

  1. Create the Trendz database in PostgreSQL:

    Terminal window
    docker compose -f docker-compose.yml exec -it postgres psql -U postgres -c "CREATE DATABASE trendz;"
  2. Create the docker-compose-trendz.yml file with the following content:

    docker-compose-trendz.yml
    services:
    trendz:
    restart: always
    image: "thingsboard/trendz:1.16.0"
    ports:
    - "8888:8888"
    environment:
    TB_API_URL: http://thingsboard:8080
    SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/trendz
    SPRING_DATASOURCE_USERNAME: postgres
    SPRING_DATASOURCE_PASSWORD: postgres
    SCRIPT_ENGINE_DOCKER_PROVIDER_URL: trendz-python-executor:8181
    SCRIPT_ENGINE_TIMEOUT: 30000
    volumes:
    - trendz-conf:/trendz-config-files
    - trendz-data:/data
    depends_on:
    postgres:
    condition: service_healthy
    trendz-python-executor:
Parameter Description
8888:8888 Trendz HTTP port
trendz-conf Docker volume for Trendz configuration
trendz-data Docker volume for Trendz data
trendz-python-executor-conf Docker volume for Trendz Python executor configuration
trendz-python-executor-data Docker volume for Trendz Python executor data

Bring up all containers (including Trendz) as a single Compose project:

Terminal window
docker compose -f docker-compose.yml -f docker-compose-trendz.yml up -d
docker compose -f docker-compose.yml -f docker-compose-trendz.yml logs -f thingsboard

Stream ThingsBoard logs:

Terminal window
docker compose -f docker-compose.yml -f docker-compose-trendz.yml logs -f thingsboard

Stream Trendz logs:

Terminal window
docker compose -f docker-compose.yml -f docker-compose-trendz.yml logs -f trendz

Stop all containers:

Terminal window
docker compose -f docker-compose.yml -f docker-compose-trendz.yml down

Start all containers:

Terminal window
docker compose -f docker-compose.yml -f docker-compose-trendz.yml up -d

Stream the ThingsBoard container logs:

Terminal window
docker compose logs -f thingsboard

Stop all containers:

Terminal window
docker compose down

Start all containers:

Terminal window
docker compose up -d

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:
thingsboard:
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: