Currency note. Figures were collected from Chinese public channels in October 2026. Where a price was quoted in CNY, the USD figure is converted at the fixed October 2026 reference rate of 1 USD ≈ 6.71 CNY. Hardware prices are indicative of order of magnitude and are not a sourcing recommendation.


"Data must not leave the plant." It shows up in industrial IoT tenders as a single line, usually in the third clause of the technical specification, with no further explanation. The integrator wins the bid, buys an industrial PC, installs the on-premises version of the IoT platform, passes acceptance, and the job looks done.

The problem is that the sentence describes where data sits. It says nothing about how data moves inside the plant. Once you place a seven-container platform on the shop-floor network, questions do not disappear because the data stays local — is MQTT in cleartext, who can reach the object-storage console, how large will the history table be in twelve months. Centralising data tends to enlarge the internal attack surface, not shrink it.

This article walks through a ThinkLink Edge (TKE) deployment in the order it actually happens. The focus is not the install command — it is the set of things that are usually discovered after the install, and that should have been settled before the machine was ordered.


1. Before You Buy Anything: Three Questions That Decide Whether You Need TKE

ThinkLink ships in three deployment forms: public-cloud SaaS (Cloud), self-hosted on a local server (TKE / ThinkLink Edge), and embedded inside a gateway (TKG). All three share the same thing models, RPC definitions and trigger logic, and assets can be migrated between them. That is what makes it safe to defer the decision — up to a point.

Dimension Cloud TKE (Edge) TKG (in-gateway)
Where it runs Public-cloud SaaS Local server / industrial PC, self-hosted Inside a ManThink gateway (e.g. GDO51 / GDI51)
Device ceiling 1,000 (free, permanently) 1,000 100
Data throughput ~100k messages/day No stated ceiling ~10k messages/day
Reference hardware Nothing to buy 8-core / 8 GB / 64 GB storage Integrated (GDI51 has 32 GB eMMC)
Connectivity Requires public internet Local, runs offline Local, no public internet needed
Best fit Evaluation, small pilots Data localisation, mid-to-large enterprises, private networks Small private deployments, brownfield retrofits, no extra server

Three questions to answer first:

Do you actually need TKE? Under 100 devices and under 10k messages a day, TKG embeds the network server directly in the gateway — no extra server, no server procurement cycle. A great many "data must not leave the plant" requirements are really about not pushing production data out through a public internet egress, and TKG satisfies that at a completely different cost structure.

Which side of 10k messages/day are you on? That line separates TKG from TKE. 1,000 devices reporting every 10 minutes is 144,000 messages a day — above Cloud's reference density and far past TKG. 50 meters reporting hourly is 1,200 a day, which TKG handles comfortably.

Who owns this machine afterwards? TKE is a standing operational commitment: OS patches, Docker engine, seven containers, certificate renewals, backups. If the customer's IT department has not explicitly accepted ownership, you have created an unowned server, usually discovered in year two when the disk is full.


2. Hardware Selection: x64 Is a Hard Constraint, Not a Recommendation

The official documentation carries two different statements of TKE's hardware requirements, and they do not agree. Worth laying out before you commit budget.

Statement A (product comparison table): reference hardware 8 cores / 8 GB RAM / 64 GB storage, minimum 2 cores and 2 GB, architecture listed as ARM64 / x64.

Statement B (Docker deployment manual; install flow updated 2026-09-11, TLS section updated 2026-10-22):

Item Requirement
Privileges root (install commands use sudo)
CPU architecture x64 only (x86_64 / amd64), minimum 2 cores
RAM minimum 4 GiB
Disk minimum 20 GiB free on the filesystem holding /opt
Network HTTPS access to package.think-link.net for online install; the offline target needs no internet
Explicitly unsupported ARM, ARM64, 32-bit x86

The two statements disagree on three points: 2 GB or 4 GB of RAM, 64 GB or 20 GB of disk, and — most consequentially — whether ARM works at all.

Follow statement B. Three reasons:

  1. Statement B comes from the deployment manual itself and is what the installer actually checks against; failing it terminates the install. Statement A is a summary line in a comparison table.
  2. Statement B is the stricter constraint. Seven containers run concurrently — EMQX, the NS bridge, PostgreSQL, Redis, ThinkLink, ThinkOne and MinIO. Two gigabytes leaves no headroom at that scale.
  3. Statement B explicitly lists ARM, ARM64 and 32-bit x86 as unsupported, and separately notes the restriction applies to both the one-line online install and the scripted offline install. Wording that specific usually comes from having tried it.

This constraint collides head-on with domestic-CPU mandates. Chinese CPUs split into two camps:

Camp Representative parts Works with TKE?
x86 Zhaoxin KX-6000/KX-7000, Hygon 3000/5000 series Yes — architecture is compatible
ARM Phytium FT-2000/4 and D2000, Kunpeng 920, Rockchip RK3568/RK3588 No — incompatible

If a localisation mandate lands on the ARM camp, TKE should be ruled out during selection, not after the machine arrives and uname -m prints aarch64. The x86 camp works directly — Hygon 3350 (8 cores / 16 threads at 3.0 GHz) is x86_64.

Indicative pricing collected from public channels in October 2026:

Configuration Purpose Indicative price
4U rackmount, i5-6500U / 8 GB / 1 TB Proof of concept (2 cores, sitting exactly on the minimum) ~$477 (¥3,200)
Industrial PC, Hygon 3350 (8C/16T) / 16 GB / 1 TB SSD Recommended for production ~$1,550–1,700 (¥10,400–11,400)
Same, with domestic OS licence Localisation-mandate projects ~$1,950 (¥13,100)

The first tier is a POC machine only. The i5-6500U is two cores / four threads, exactly the stated minimum; CPU becomes the bottleneck before the disk does.


3. The Disk Calculation: 20 GiB Is the Entry Ticket, Not the Plan

The 20 GiB check is the installer's admission gate. Real consumption comes from three sources.

Seven container images. The offline bundle accepted on 2026-09-11 for version 2.00.062 is about 2.45 GB, holding the application archive, the Compose file and seven image archives — nine files total. Later versions will differ.

Database growth. At 1,000 devices reporting every 10 minutes, that is 144,000 rows a day. At roughly 1 KB per row including indexes, about 144 MB/day, or ~52 GB a year. Add PostgreSQL WAL, index bloat and history-query overhead and the usual practice is to provision two to three times that.

MinIO object storage. Reports and images live in the Docker named volume minio_data. This swings wildly depending on whether the business generates reports and how often.

Sum them and 20 GiB covers a few months. Go to a 1 TB SSD for production. The price delta sits in the table above and is trivial against total project value; the alternative is an online capacity expansion in year two.

One detail that is easy to miss: object files live in a Docker named volume, so routine backups must cover that volume; backing up the /opt directory alone does not substitute for object data. A backup script that only walks a directory path will silently lose every report file.


4. Port Planning: "Not Leaving the Plant" Is Not the Same as "Not on a Network"

This is the section worth reading twice. On-premises deployment solves data residency. A default install then opens a full set of ports on the host, and a meaningful share of them are cleartext.

Complete the HTTP install first, then configure HTTPS with tkl-tls 2.0.0 — that is the documented order. Host inbound ports:

Port Protocol Purpose Notes
80 (or 8080) TCP ThinkLink web / API over HTTP Original entry; if 80 is taken the installer interactively offers 8080; retained after TLS
443 TCP ThinkLink web / API over HTTPS Enabled once tkl-tls 2.0.0 configures the in-container Nginx
1700 UDP LoRaWAN GWMP gateway uplink Open per gateway access needs
1883 TCP Device MQTT (cleartext) Open per device access needs
8883 TCP Device MQTTS Not published by default; configure and verify separately in EMQX
8083 TCP MQTT over WebSocket Open per client needs
8084 TCP MQTT over WSS Path /mqtt; requires its own certificate
18083 TCP EMQX dashboard over HTTP Retained; not automatically upgraded to HTTPS
18084 TCP EMQX dashboard over HTTPS Enabled by tkl-tls 2.0.0
9000 TCP MinIO S3 API Restrict source addresses
9001 TCP MinIO console Trusted administrator networks only

Details that belong in the plan:

Port conflicts are handled inconsistently. If 80 is taken, the installer asks whether to use 8080 and leaves the occupying service alone. But if 9000 or 9001 is taken, the installer stops outright and will not pick an alternative. A target machine already running another storage service will stall mid-install.

5432 and 6379 never need to be exposed. PostgreSQL and Redis ports are container-internal only.

Management HTTPS is not device MQTTS. tkl-tls produces 443 and 18084. Device-side 8883 and 8084 are unpublished by default and need certificates uploaded in EMQX, mappings opened and connectivity verified. Replacing the certificate in the management UI does not replace device listener certificates — those are two separate configurations.

An open port is not an enabled TLS listener. Worth copying the manual's reminder straight into the acceptance sheet.

The EMQX console at 18083 stays HTTP. The HTTPS console is 18084; the old entry is retained. Locking down 18083 while forgetting 18084 accomplishes nothing.


5. On-Premises Deployment ≠ Regulatory Compliance

This is the most common misreading of "data must not leave the plant."

Moving the platform inside the plant addresses storage location. The path from sensor to platform is still network transmission, still subject to whatever the applicable rules require of transmission.

China's Interim Measures for Data Security Management in the Industry and Information Technology Sector (MIIT Network Security Circular No. 166, issued 2022-12-08, effective 2023-01-01) classifies sector data into three tiers — general, important and core — and states in Article 17:

Data processors shall formulate security policies and adopt protective measures based on the type, level and application scenario of transmitted data. When transmitting important data or core data, they shall adopt verification technology, cryptographic technology, secure transmission channels or secure transmission protocols.

Read that against the port table above. Under a default install, device MQTT runs cleartext on 1883, HTTP runs on 80, and MinIO's S3 API on 9000. If this system carries data classified as important, on-premises deployment alone does not satisfy Article 17 — the transmission channels have to be closed as well, meaning web/API on 443 and device MQTT on 8883.

The Network Data Security Regulations (State Council Decree No. 790, published 2024-09-24, effective 2025-01-01, nine chapters and 64 articles) establishes the classification-and-grading regime one level up, with a dedicated chapter on important data.

Two further clauses land on concrete operations:

For European readers the pressure arrives from a different direction. The EU Data Act's design obligation for data access (Article 3(1)) took effect on 2026-09-12, with cloud switching charges falling to zero on 2027-01-12. Different instrument, same structural conclusion: the ability to move a deployment — including moving it onto your own hardware — is becoming a compliance matter, not an architecture preference.

The three clauses together form a chain: local deployment is step one, TLS is step two, backup and log retention are step three. Declaring compliance after step one is what gets caught in an audit.


6. Two Install Paths: Online One-Liner and Scripted Offline

Online

On a connected server, no arguments needed:

curl --tlsv1.2 --tls-max 1.2 -fsSL https://package.think-link.net/install.sh | sudo bash

The installer: detects OS, CPU, RAM, disk and ports → installs Docker on supported systems (reusing any working Docker) → downloads the application archive, the Compose file and seven image archives (nine files) → installs to the target directory, loads images and starts Compose → checks ThinkLink HTTP, MinIO readiness and bucket initialisation → records version and access information.

MinIO creates a private bucket named thinklink on first start.

Scripted offline

The documentation summarises it as "download online → transfer and verify → install offline."

Step one, on a connected machine. The download mode must run from a local script file, never through curl | bash, because the bundle has to carry the same complete installer:

curl --fail --silent --show-error --proto '=https' \ --tlsv1.2 --tls-max 1.2 --connect-timeout 10 --max-time 60 \ https://package.think-link.net/install.sh -o thinklink-install.sh

bash thinklink-install.sh --help bash thinklink-install.sh --download-only ./thinklink-offline

Run --help first and confirm it lists --download-only, --verify-only and --offline. The target directory must not yet exist and its parent must; do not mkdir it beforehand.

The delivered directory holds 13 checksummed files:

File Role
application.tar Application archive
docker-compose.yml Compose definition
tkl-emqx.tar / tkl-nsbrg.tar / tkl-postgres.tar EMQX, NS bridge, PostgreSQL images
tkl-redis.tar / tkl-thinklink.tar / tkl-thinkone.tar Redis, ThinkLink, ThinkOne images
tkl-minio.tar MinIO image
install.sh / install-offline.sh Installer scripts
release.json Release id, version, channel, architecture
SHA256SUMS Covers 9 artifacts, 2 scripts, the version record and the readme
README.txt In-bundle notes

Step two, transfer and verify. Move the directory intact — it is created with mode 0700 and should stay read-restricted afterwards. On the target:

cd thinklink-offline bash install.sh --verify-only .

This mode needs no root, no Docker and makes no network requests. It checks file integrity, manifest paths and version format, and only proceeds if all pass. SHA-256 verifies transfer integrity; it is not a publisher signature and does not independently prove provenance — a candid note in the manual, and a reminder that supply-chain trust still rests on the delivery channel.

Step three, install. Run sudo bash install-offline.sh in the bundle directory, adding --yes for unattended runs (it skips only the final confirmation prompt, not verification or port checks).

The offline target must already have Docker Engine and Docker Compose V2, because the bundle does not include Docker or OS dependencies. Check first:

uname -m sudo docker version sudo docker compose version

uname -m must print x86_64. Anything else: stop.

Three limits of the offline path

  1. New installations only — no automatic upgrade, no rollback on failure. If it detects an existing install or leftover data, it leaves the scene intact for you to investigate rather than cleaning up and retrying. Upgrades need new artifacts, a backup and a version-matched upgrade plan.
  2. Do not mix download batches. The package service checks upstream at 00:00 Beijing time daily and updates artifacts. Mixing batches produces OFFLINE_IMAGES_MISSING — Compose and images out of sync.
  3. No resumable downloads across processes. A failure means re-downloading the whole 2.45 GB. On an expired URL or single-file failure, the script refreshes the address within the same session and retries once.

7. The One Red Line When Running Alongside Cloud

Most projects pass through a transition period with a foot in both camps — legacy devices in the cloud, new devices on-premises, both live.

The documentation is unambiguous:

Do not enable the same LoRaWAN device profile on two platforms at once. If TKE and the cloud platform both respond to Join or Confirm messages, join failures and downlink conflicts can result. When switching platforms, disable or delete the profile on the one you are not using.

This is a functional constraint, not a performance tip. A Join Request is forwarded to every NS registered for that DevEUI. Both answer with a Join Accept; the device accepts one, but the other NS now believes the device joined and holds frame counters — subsequent downlinks go to the wrong path.

During transition, the profile is enabled on exactly one side. Not "both on, whoever answers first."


8. Cloud → Edge Migration: Three Traps in the Excel Import/Export

ThinkLink moves bulk data through Excel across six module types: device configurations, LoRaWAN profiles, thing models, RPC commands, linkage/trigger models and device templates. The workflow is identical on Cloud, TKE and TKG — the only difference being that TKE/TKG have their own local admin account, unrelated to the cloud one.

  1. In the cloud, open the target module (e.g. LoRaWAN Profiles)
  2. Select the entries to sync (none selected = export all)
  3. Click Export and download the generated spreadsheet
  4. Repeat 2–3 for each data type (thing models, RPC commands, …)
  5. Switch to TKE and open the matching module
  6. Click Import and choose the spreadsheet
  7. Confirm the import completed without errors
  8. Importing public models requires logging in as admin

Three traps:

Trap one: DevEUI is globally unique, so cross-organisation migration is delete-then-import. A given DevEUI belongs to one organisation within a platform. Moving a profile from organisation A to B requires deleting it in A first; otherwise the import fails outright.

Data type Delete first? Why
LoRaWAN Profiles Yes DevEUI is globally unique
Thing models / RPC commands / device templates No Same ID means overwrite; not uniqueness-constrained

Trap two: a matching ID means full overwrite, and it cannot be rolled back. The rule is "create if the ID is absent, overwrite completely if present." That is a replacement, not a merge. Stale field values in the spreadsheet will overwrite live configuration on the target.

There is exactly one mitigation: export first, before importing, and keep that spreadsheet as the backup. Validate format on a small batch before the first large import.

Trap three: there is no undo. With a backup, re-import it. Without one, rebuild the configuration by hand. Review the ID column row by row so the file contains only what you intend to create or update.


9. Backups: Three Layers That Do Not Substitute for One Another

Layer Location Method
Configuration and install record Install directory under /opt File-level backup
Database PostgreSQL container volume Volume snapshot or logical dump
Object files Docker named volume minio_data Volume-level backup

Backing up /opt alone does not substitute for object data. A container restart preserves existing buckets and objects; host disk failure does not.

Article 15 of Circular 166 requires disaster-recovery backup and periodic recovery testing. Note the second half — a backup that has never been restored is a hypothesis. One way to exercise the whole chain during acceptance is generating and downloading a report:

sudo docker compose -f exec -T minio /thinklink-minio check-ready

That command checks whether the image's built-in initialisation completed; pair it with a container status check.


10. Error Codes Worth Recognising

The manual lists the full set. These are the ones that surface during deployment:

Message Meaning and handling
OFFLINE_OUTPUT_EXISTS Download directory already exists — pick one that does not; do not overwrite the old bundle
SCRIPT_FILE_REQUIRED Download mode must run from a local script file, not curl \| bash
ARTIFACT_DOWNLOAD_FAILED Check network and disk space, re-download the whole set
DOWNLOAD_REFRESH_INVALID Version or artifacts changed while refreshing — re-download the full bundle
OFFLINE_BUNDLE_INVALID / OFFLINE_CHECKSUM_FAILED Re-transfer the complete directory; do not edit the manifest to bypass
OFFLINE_DOCKER_REQUIRED Install offline dependencies, start Docker, verify Compose V2
OFFLINE_EXISTING_INSTALL Existing install or data present — prepare a backup and upgrade plan first
PORT_IN_USE / ALTERNATE_PORT_IN_USE Resolve the conflict, arrange a usable port, retry
OFFLINE_IMAGES_MISSING Compose and images out of sync — supply a matching full bundle
HEALTH_CHECK_FAILED Check container status and logs; preserve install data while investigating

Two for day-to-day work:

sudo docker compose -f ps sudo docker compose -f logs

Check logs for connection strings and credentials before sharing them externally — a reminder the manual makes on its own.


11. Acceptance Checklist

In the order of this article, a TKE deployment ready to hand over:

# Item Pass criterion
1 uname -m prints x86_64 Non-x64 fails outright
2 CPU ≥ 2 cores, RAM ≥ 4 GiB, /opt ≥ 20 GiB Production: 8 cores / 16 GB / 1 TB
3 Pre-flight port check on 80/8080, 9000, 9001, 1700, 1883 A 9000/9001 conflict aborts the install
4 All seven containers running docker compose ps
5 Private MinIO bucket ready, anonymous access refused check-ready plus an anonymous access attempt
6 Web/API on HTTPS 443, EMQX console on 18084 tkl-tls 2.0.0
7 Device MQTT on 8883 (where required) Configured and verified separately in EMQX
8 MinIO 9000/9001 reachable only from trusted networks Firewall rules
9 No device profile enabled on both cloud and TKE Profile inventory cross-check
10 Export taken before import Backup file retained
11 Backup scope covers the minio_data volume Backup script review
12 One recovery test completed Recovery drill record
13 Default passwords changed (ThinkLink / EMQX / MinIO) Business client configs updated to match
14 Full offline bundle + release.json + SHA256SUMS retained Version traceability

Item 5's "anonymous access to the private bucket refused" was explicitly covered in the vendor's own 2026-09-11 acceptance record, and it belongs on your checklist too. A private bucket that is anonymously readable is every report file sitting in an internal share.


12. Closing

"Data must not leave the plant" is a requirement about storage location, and it triggers three consequences: you buy the machine, you close the transmission channels, and you run the backups. Only the first of those is a procurement problem.

Two points this article has argued repeatedly:

On-premises is not the same as compliant. Article 17 of Circular 166 requires secure transmission channels or protocols for important data. A default TKE install runs MQTT in cleartext on 1883 and HTTP on 80. tkl-tls is not an optional hardening step; it is what closes that clause.

Confirm the x64 constraint before the purchase order. The vendor's own documentation carries two conflicting statements about TKE's hardware requirements, and they disagree on whether ARM works. Taking the deployment manual as authoritative: it does not. If a localisation mandate has already settled on Phytium or Kunpeng, raise it at proposal stage rather than when uname -m prints aarch64.

TKE's value is that it bundles the network server, thing models, trigger logic, alarms and object storage into one Compose command while preserving a migration path to and from both the cloud and the in-gateway form. The price is that someone now owns it. Deciding who, before buying anything, matters more than the spec sheet.

Next in the series (Issue 24): the data is local; now let the rest of the building read it — BACnet/IP and Modbus TCP integration on ThinkLink, from field mapping to commissioning with YABE.


Sources