Add an IoT Edge Device on Ubuntu
On Ubuntu the Azure IoT Edge runtime runs natively on the host. No virtual machine is involved, unlike the Windows with EFLOW setup.
The installation script install-iot-edge.sh prepares everything the device needs to enroll: the Microsoft package repository, the container engine, the IoT Edge runtime, the volume directories and the provisioning configuration. No manual module configuration is required. Broker, storage, certificate and telemetry settings are delivered to the device by the Datalogic Connect deployment manifest when the device is enrolled.
Prerequisites
Before you begin
-
Create an Edge Device in Device Visibility. The Serial Number you enter here becomes the Edge Device ID. The Device IP must be the static IP address of the Ubuntu host, because the ProvisioningModule issues the server certificate for that address.
-
Make sure the host meets the hardware requirements for the number of devices it will manage.
-
Make sure you have superuser privileges on the host. The installation must run as
root. -
Open the device's Overview page in Connect. From here you download the installation script and, if you need it, the credentials file.
Start with Authentication.
Provisioning values
The installer needs only the following three values. When you download the script from the device's Overview page, Connect embeds all three, so you normally do not have to supply them yourself.
| Value | Where it comes from | Where it is used |
|---|---|---|
| Scope ID | scope in the Get Credentials JSON export | DPS id_scope in /etc/aziot/config.toml |
| Primary Key | primaryKey in the Get Credentials JSON export | DPS symmetric_key in /etc/aziot/config.toml |
| Edge Device ID | The Serial Number you entered when creating the device. It is not part of the export. | DPS registration_id in /etc/aziot/config.toml |
Earlier versions of this procedure also required the Organization ID, the SAS Devices Key, the SAS Smart Enrollment Key, the SAS Edge Storage Key, a certificate common name and a fixed server IP address. None of them is needed on the device anymore. The backend resolves them and delivers the resulting module configuration through the deployment manifest at enrollment time. For the same reason the installer no longer accepts --hostname and --ip.
Supported OS and Architecture
| OS | Architecture | Status |
|---|---|---|
| Ubuntu 22.04 LTS (Jammy Jellyfish) | x86_64 | ✅ Verified |
| Ubuntu 24.04 LTS (Noble Numbat) | x86_64 | ✅ Verified |
The installation script exits on any other distribution or Ubuntu release. Make sure the host runs one of the versions listed above before you start.
Network requirements
The edge device must be able to reach the outbound endpoints listed under Cloud Endpoints and, for the install script, under Installation Endpoints.
If the device is behind a corporate firewall, allow all the outbound endpoints above. The IoT Edge runtime selects the best available upstream protocol, MQTT TLS on port 8883 or HTTPS on port 443. Field devices also need to reach the edge device on the local network. If a host firewall such as ufw is active, allow the inbound ports listed in Network Requirements.
Quick install
The installation is automated. The script installs the container engine and the IoT Edge runtime, creates the volume directories and provisions the device against Azure DPS.
1. Download the installation archive
Open the device's Overview page in Connect, click Install script and choose Linux. The archive contains install-iot-edge.sh, its SHA-256 checksum and a README.
Copy the archive to the device, extract it and verify the checksum:
tar -xzf <archive-name>.tar.gz
sha256sum -c install-iot-edge.sh.sha256
2. Run the installer
The script downloaded from Connect already contains the Scope ID, the Edge Device ID and the Primary Key of the device, so no option is required:
sudo bash install-iot-edge.sh
The script prints a summary of the resolved values and asks Proceed with installation? [y/N]. Answer y to start.
The installer can be re-run, but its first step deletes the whole content of /srv. Do not run it on a device that holds data you need under that path, and do not store custom data under /srv.
Supplying the values yourself
If the script does not contain the provisioning values, for example because you obtained it from another source, you can supply them in three ways.
-
Credentials file next to the script. Download the Get Credentials JSON export from the device's Overview page, save it as
edge-credentials.jsonin the same folder as the script and run the script without options. The script detects the file and prompts only for the serial number. -
Credentials file in another location. Point the script at the file and pass the serial number:
sudo bash install-iot-edge.sh \--config "/path/to/credentials.json" \--serial-number "<SERIAL_NUMBER>" -
All three values on the command line.
sudo bash install-iot-edge.sh \--scope-id "<SCOPE_ID>" \--serial-number "<SERIAL_NUMBER>" \--primary-key "<PRIMARY_KEY>"
The credentials export looks like this. Pass it exactly as downloaded:
{
"createdAt": "2026-09-02T15:04:14.989Z",
"data": [
{ "label": "scope", "value": "0ne0XXXXXXX" },
{ "label": "primaryKey", "value": "<PRIMARY_KEY>" }
]
}
The export carries the Scope ID and the Primary Key, but not the Edge Device ID. Anything still missing after all sources are merged is asked interactively.
Parameter table
The installation script accepts the following options. Run sudo bash install-iot-edge.sh --help on the device to print the same list.
| Option | Description | Notes |
|---|---|---|
--config | Path to the Get Credentials JSON export. Supplies the Scope ID and the Primary Key. | --json is an alias. If omitted, edge-credentials.json next to the script is used. |
--serial-number | Edge Device ID, that is the Serial Number of the device. | Not part of the credentials export. --device-id is an alias. |
--scope-id | DPS ID Scope. | Overrides the value read from the credentials file. |
--primary-key | DPS symmetric primary key. | Overrides the value read from the credentials file. |
--help | Print the usage message and exit. |
The sources are merged. Each value is taken from the highest-ranked source that supplies it:
--scope-id,--serial-numberand--primary-keyon the command line- The values embedded by Connect at download time
- The JSON export passed with
--config - An
edge-credentials.jsonfile next to the script - The configuration saved by a previous run in
/etc/connect/install-edge.env - Interactive prompts, for anything still missing
After collecting the values, the script saves them to /etc/connect/install-edge.env with mode 600, because the file contains the primary key. On a later run without command-line values or a credentials file, the script shows the saved configuration and offers to reuse it. In every other case the saved file is used only as a fallback for the values that are still missing.
3. What the script does
- Pre-cleanup. Stops the IoT Edge service, removes any existing edge-agent container and wipes
/srv/*, so a re-run always starts from a clean state. - System update. Runs
apt-get updateandapt-get upgrade. - Runtime installation. Registers the Microsoft package repository for the detected Ubuntu release, then installs
moby-engine(ordocker.ioifmoby-engineis unavailable) andaziot-edge. Packages already present are skipped. - Docker daemon configuration. Writes
/etc/docker/daemon.jsonwith thelocallog driver and a rolling policy of 5 files of 10 MB, then enables and restarts the Docker service so that the policy applies from this run onward. - Directory structure. Creates the volume directories bound by the deployment manifest and applies the ownership each container image expects. The table below lists them.
- Provisioning configuration. Writes
/etc/aziot/config.tomlwith the DPS symmetric-key provisioning block, the image garbage collection settings and the bootstrapedgeAgentimage. - Apply. Runs
iotedge config apply.
The directory step creates the following paths and sets their ownership:
| UID | Directories | Used by |
|---|---|---|
1000 | /srv/redis, /srv/MqttTranslationModule/*, /srv/DeviceHubModule/*, /srv/StorageModule/log, /srv/ProvisioningModule/log, /srv/shared/download, /srv/edgeAgent, /srv/edgeHub, /srv/DockerRegistry/registry | Gateway modules, Redis, edgeAgent and edgeHub storage, registry data |
1001 | /srv/shared/certs, /srv/shared/certs/server | Shared certificates, written by ProvisioningModule and read by nanomq |
11000 | /srv/blobstorage and its scan_avoidance, ticket_swithing and produce_recognition subdirectories | Local blob storage of the Smart Vision manifest |
The /srv/blobstorage directories and /srv/DockerRegistry/registry are used only by the Smart Vision manifest. Creating them on a base edge gateway adds only a few empty directories and keeps a single procedure valid for both manifests.
The ticket_swithing spelling is the one used by that manifest. The host path must match it exactly, otherwise the bind mount points to a different directory.
The full run is logged to /var/log/install-edge.log.
4. Enroll the device
When the script finishes, wait a few minutes before enrolling the edge device in the Connect portal. IoT Edge must complete the DPS provisioning and start edgeAgent before it can receive the deployment manifest. Enrolling too early can leave the modules unconfigured.
Check that edgeAgent is running before you enroll:
sudo iotedge list
After the enrollment, follow Verify the installation.
Verify the installation
After the enrollment, Connect applies the deployment manifest and the modules are pulled. Wait at least two minutes, then list the IoT Edge modules:
sudo iotedge list
All modules should reach the running state:
NAME STATUS DESCRIPTION CONFIG
DeviceHubModule running Up 2 hours <registry>/device-hub-module:<version>
MqttTranslationModule running Up 2 hours <registry>/mqtt-translation-module:<version>
ProvisioningModule running Up 2 hours <registry>/provisioning-module:<version>
StorageModule running Up 2 hours <registry>/storage-module:<version>
edgeAgent running Up 2 hours <registry>/azureiotedge-agent:<version>
edgeHub running Up 2 hours <registry>/azureiotedge-hub:<version>
nanomq running Up 2 hours <registry>/nanomq:<version>
otelcollector running Up 2 hours <registry>/opentelemetry-collector-contrib:<version>
redis running Up 2 hours <registry>/redis:<version>
The module set and the image tags come from the manifest selected as Active manifest when the device was created, so they differ between manifests. The listing above belongs to the Smart Vision manifest. A base edge gateway does not run the blobstorage* and registry modules.
If a module stays in failed or keeps restarting, inspect it:
sudo iotedge logs <module-name>
The full installation log is available at /var/log/install-edge.log.
Uninstall
The following commands undo what install-iot-edge.sh did: they stop the modules, remove the IoT Edge runtime and delete the data and configuration files. Run them as root or with sudo. Only the objects created by the installer are touched: other containers and images on the host are left alone.
Step 2 deletes the module volumes under /srv, including certificates, logs, blob storage and registry data. The Edge Device in Connect is not affected: see step 4.
1. Stop IoT Edge and remove the modules
Stop the runtime, then remove the containers managed by edgeAgent, their images and the IoT Edge network:
sudo iotedge system stop
sudo docker ps -aq -f "label=net.azure-devices.edge.owner=Microsoft.Azure.Devices.Edge.Agent" | xargs -r sudo docker rm -f
sudo docker images -q "crsolinfraprodeuw.azurecr.io/*" | xargs -r sudo docker rmi -f
sudo docker images -q "mcr.microsoft.com/azureiotedge-*" | xargs -r sudo docker rmi -f
sudo docker network rm azure-iot-edge
2. Remove the IoT Edge runtime, its configuration and the data
Purge the packages, delete their configuration, state and system users, then the module volumes, the saved installer configuration and the logs:
sudo apt-get purge -y aziot-edge aziot-identity-service
sudo rm -rf /etc/aziot /var/lib/aziot /run/aziot /var/log/aziot
for u in aziotks aziotcs aziotid aziottpm iotedge; do sudo userdel "$u" 2>/dev/null; done
sudo groupdel aziot 2>/dev/null
sudo rm -rf /srv/{redis,MqttTranslationModule,DeviceHubModule,StorageModule,ProvisioningModule,shared,edgeAgent,edgeHub,DockerRegistry,blobstorage}
sudo rm -rf /etc/connect /var/log/install-edge.log /var/log/cloud-init-output-iot.log
sudo apt-get autoremove -y --purge
A host set up with an installer earlier than 2.0.0 also has /srv/mosquitto, /srv/otel, /usr/local/bin/configure-redis.sh and /var/run/configure-redis.pid. Remove them as well: nothing recreates them.
3. Optional: remove the container engine and the Microsoft repository
Skip this step if Docker is used by anything else on the host. Removing the engine also deletes every image and container under /var/lib/docker. The Microsoft repository serves moby-engine, so remove it only together with the engine. If you keep the engine, /etc/docker/daemon.json written by the installer stays in place.
sudo systemctl disable --now docker.service docker.socket containerd.service
sudo apt-get purge -y moby-engine moby-cli moby-buildx moby-compose moby-containerd moby-runc docker.io
sudo rm -rf /var/lib/docker /var/lib/containerd /etc/docker
sudo groupdel docker 2>/dev/null
sudo apt-get purge -y packages-microsoft-prod
sudo apt-get autoremove -y --purge
sudo apt-get update
4. Delete the device in Connect
The host is now clean, but the Edge Device still exists in the portal. If you are not going to reinstall it, delete it from the Device List.