Skip to main content

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​

  1. 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.

  2. Make sure the host meets the hardware requirements for the number of devices it will manage.

  3. Make sure you have superuser privileges on the host. The installation must run as root.

  4. Open the device's Overview page in Connect. From here you download the installation script and, if you need it, the credentials file.

If this is your first time using Connect

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.

ValueWhere it comes fromWhere it is used
Scope IDscope in the Get Credentials JSON exportDPS id_scope in /etc/aziot/config.toml
Primary KeyprimaryKey in the Get Credentials JSON exportDPS symmetric_key in /etc/aziot/config.toml
Edge Device IDThe Serial Number you entered when creating the device. It is not part of the export.DPS registration_id in /etc/aziot/config.toml
Migrating from earlier versions

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​

OSArchitectureStatus
Ubuntu 22.04 LTS (Jammy Jellyfish)x86_64✅ Verified
Ubuntu 24.04 LTS (Noble Numbat)x86_64✅ Verified
OS compatibility

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.

Firewall configuration

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.

Pre-cleanup

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.json in 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.

OptionDescriptionNotes
--configPath 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-numberEdge Device ID, that is the Serial Number of the device.Not part of the credentials export. --device-id is an alias.
--scope-idDPS ID Scope.Overrides the value read from the credentials file.
--primary-keyDPS symmetric primary key.Overrides the value read from the credentials file.
--helpPrint the usage message and exit.

The sources are merged. Each value is taken from the highest-ranked source that supplies it:

  1. --scope-id, --serial-number and --primary-key on the command line
  2. The values embedded by Connect at download time
  3. The JSON export passed with --config
  4. An edge-credentials.json file next to the script
  5. The configuration saved by a previous run in /etc/connect/install-edge.env
  6. Interactive prompts, for anything still missing
Saved configuration

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​

  1. 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.
  2. System update. Runs apt-get update and apt-get upgrade.
  3. Runtime installation. Registers the Microsoft package repository for the detected Ubuntu release, then installs moby-engine (or docker.io if moby-engine is unavailable) and aziot-edge. Packages already present are skipped.
  4. Docker daemon configuration. Writes /etc/docker/daemon.json with the local log 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.
  5. Directory structure. Creates the volume directories bound by the deployment manifest and applies the ownership each container image expects. The table below lists them.
  6. Provisioning configuration. Writes /etc/aziot/config.toml with the DPS symmetric-key provisioning block, the image garbage collection settings and the bootstrap edgeAgent image.
  7. Apply. Runs iotedge config apply.

The directory step creates the following paths and sets their ownership:

UIDDirectoriesUsed by
1000/srv/redis, /srv/MqttTranslationModule/*, /srv/DeviceHubModule/*, /srv/StorageModule/log, /srv/ProvisioningModule/log, /srv/shared/download, /srv/edgeAgent, /srv/edgeHub, /srv/DockerRegistry/registryGateway modules, Redis, edgeAgent and edgeHub storage, registry data
1001/srv/shared/certs, /srv/shared/certs/serverShared certificates, written by ProvisioningModule and read by nanomq
11000/srv/blobstorage and its scan_avoidance, ticket_swithing and produce_recognition subdirectoriesLocal blob storage of the Smart Vision manifest
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>
Module set

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.

Data loss

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
Installers before 2.0.0

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.