Migrating from the legacy all-in-one tb-pe image
Older ThingsBoard PE Docker deployments run a single all-in-one container image (thingsboard/tb-pe) that bundles the core platform and the report engine together. Current installations and the version upgrade steps assume the split layout — thingsboard/tb-pe-node (core platform) and thingsboard/tb-pe-web-report (report engine) as two separate services.
Who needs this guide
Section titled “Who needs this guide”thingsboard/tb-pe was published up to 4.2.1PE (2025-10-14) and stopped there, while thingsboard/tb-pe-node continued through 4.2.1.1PE, 4.2.2.x, and all of 4.3.x. You need this guide if your docker-compose.yml still references thingsboard/tb-pe:<current-tag> as a single service, with no separate report container:
Full example of the old docker-compose.yml
services: mytbpe: restart: always image: "thingsboard/tb-pe:4.2.0PE" ports: - "8080:8080" - "1883:1883" - "8883:8883" environment: TB_QUEUE_TYPE: in-memory SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/thingsboard TB_LICENSE_SECRET: PUT_YOUR_LICENSE_SECRET_HERE TB_LICENSE_INSTANCE_DATA_FILE: /data/license.data volumes: - /path/to/thingsboard/.mytbpe-data:/data - /path/to/thingsboard/.mytbpe-logs:/var/log/thingsboard postgres: restart: always image: "postgres:15" ports: - "5432" environment: POSTGRES_DB: thingsboard POSTGRES_PASSWORD: postgres volumes: - /path/to/thingsboard/.mytbpe-data/db:/var/lib/postgresql/dataSwitch to the split layout before starting any version upgrade — the per-version steps don’t apply to the all-in-one image as-is.
-
Note your current PE version tag (the tag after
thingsboard/tb-pe:) — you’ll reuse it for both new services below without changing the version yet. -
Change your existing service’s image from
thingsboard/tb-pe:<current-tag>tothingsboard/tb-pe-node:<current-tag>. -
Add
REPORTS_SERVER_ENDPOINT_URL: http://tb-web-report:8383to that service’senvironment:block. Keep all your other existing environment variables (license, MQTT/CoAP/LWM2M settings, etc.) unchanged. -
Add a new
tb-web-reportservice underservices:. This is the minimum working definition — the reference compose file in the Docker installation guide additionally sets logging and report timeout options you can copy across if you want to match it exactly:tb-web-report:restart: alwaysimage: "thingsboard/tb-pe-web-report:<current-tag>"depends_on:- <your-thingsboard-service-name>environment:HTTP_BIND_ADDRESS: 0.0.0.0HTTP_BIND_PORT: 8383DOCKER_MODE: true -
Pull the new images and restart:
Terminal window docker pull thingsboard/tb-pe-node:<current-tag>docker pull thingsboard/tb-pe-web-report:<current-tag>docker compose up -d -
Confirm the platform comes up cleanly on your current version with the new two-container layout — same data, same license, same dashboards and devices — before proceeding to the version upgrade steps.
Optional: moving from local folder bind mounts to Docker named volumes
Section titled “Optional: moving from local folder bind mounts to Docker named volumes”The steps above only require touching the image and adding the report service — your existing volumes stay as-is. If you’d also like to match the current reference compose file’s use of Docker named volumes instead of local folder bind mounts, do this as a separate step, after confirming the image-split switch works:
-
Stop the stack before copying any data — copying a live PostgreSQL data directory can produce a corrupt snapshot:
Terminal window docker compose stop -
Create named volumes for your database and license data:
Terminal window docker volume create --name tb-postgres-datadocker volume create --name tb-pe-license-data -
Copy your existing bind-mounted data into the new volumes (adjust the source paths to match your current
docker-compose.yml;799is the user ID of the ThingsBoard non-root Docker user):Terminal window docker run --rm -v /path/to/thingsboard/.mytbpe-data/db:/source -v tb-postgres-data:/destination alpine sh -c "cp -a /source/. /destination/"docker run --rm -v /path/to/thingsboard/.mytbpe-data:/source -v tb-pe-license-data:/destination alpine sh -c "cp -a /source/license.data /destination/ && chown 799:799 /destination/license.data"Your
/var/log/thingsboard(or.mytbpe-logs) bind mount doesn’t need this treatment — leave it as a local folder mount, or drop it entirely and rely on the Docker logging driver, as the reference compose file does. -
Update your
docker-compose.yml: reference the named volumes on the services (postgres-data:/var/lib/postgresql/dataon postgres,license-data:/dataon the ThingsBoard node), and declare them at the top level with pinned names so Compose reuses the volumes created above instead of creating new project-prefixed ones:volumes:postgres-data:name: tb-postgres-datadriver: locallicense-data:name: tb-pe-license-datadriver: local -
Restart:
Terminal window docker compose up -d
Was this helpful?