AWS IoT is the best fit when you need a cloud update server to host firmware, manage device cohorts, and orchestrate staged rollouts. If you want a provider to handle hosting and delivery with less setup, Golioth is recommended, though evidence shows less emphasis on deployment orchestration.
3AWS IoTBest when you need a secure cloud update server to host firmware, manage device cohorts, and orchestrate staged rollouts; evidence cites AWS IoT for server-side deployment and staging. Tradeoff: setup and cloud dependency.38%
For a fleet, treat OTA as a secure deployment system, not merely “download a new .bin and reboot.” A robust design needs four pieces: firmware packaging/signing, a device-side boot/update mechanism, a distribution/control plane, and staged rollout/rollback.
This is broadly the model used by current embedded OTA systems. For example, Zephyr's OTA documentation describes downloading a signed image into an unused flash partition and having MCUboot verify it before booting; Mender similarly uses redundant A/B images and rollback mechanisms.
To implement over-the-air (OTA) firmware updates for an embedded fleet, you must configure a dual-partition (A/B) storage layout on each device, build a safe bootloader with fallback protection, and connect the fleet to a central management server. [](]()]()
Implementing over-the-air (OTA) firmware updates for a fleet of embedded devices requires a robust, secure, and fault-tolerant architecture spanning the device, the transport layer, and the backend cloud infrastructure.
Here is a structured, step-by-step roadmap to implement a reliable OTA system:
Implementing over-the-air (OTA) firmware updates for an embedded fleet requires a robust architecture combining a dual-bank flash memory layout, a secure bootloader, cryptographic image verification, and a reliable device management backend. [](]()](]()]()
1. Put a secure bootloader underneath your application
For an MCU, MCUboot is a strong starting point, particularly if you're using Zephyr, because it already understands signed images and upgrade/revert workflows. Zephyr provides direct MCUboot integration and requires appropriate flash partitions for the primary and secondary image slots.
A typical flash layout is:
┌──────────────────────┐
│ Immutable bootloader │
├──────────────────────┤
│ Application slot A │ ← currently running
├──────────────────────┤
│ Application slot B │ ← downloaded update
├──────────────────────┤
│ Settings / metadata │
└──────────────────────┘
The device should never execute an OTA image merely because the download succeeded.
Instead:
download
↓
check size
↓
check hash
↓
verify digital signature
↓
check hardware/product compatibility
↓
mark image as "test"
↓
reboot
↓
bootloader validates image
↓
application starts
↓
health check succeeds?
├── yes → mark image confirmed
└── no → revert to previous image
Zephyr's MCUmgr/MCUboot flow, for example, explicitly supports uploading an image, marking it for testing, rebooting, and subsequently confirming it.
The signing key is extremely important
Do not put your firmware-signing private key on devices or in ordinary developer machines.
You should also protect against power loss during the download and power loss during installation. A/B slots are particularly useful here because the device can continue booting the known-good image while the inactive slot is being programmed. Mender's documentation describes this redundant-partition approach specifically as a way to recover from interrupted updates and power loss.
5. Don't skip the post-reboot health check
This is one of the most important parts.
Suppose version 4.2 is successfully downloaded and cryptographically valid—but crashes immediately after boot.
IF rollback_rate > threshold
PAUSE rollout
IF post_update_disconnects > threshold
PAUSE rollout
IF signature/verification failures > threshold
STOP rollout
Cloud fleet-management systems such as AWS IoT Jobs support targeting and monitoring deployments; AWS also documents continuous OTA targeting based on device attributes.
7. Protect the OTA mechanism itself
At minimum I'd want:
Layer
Protection
Device identity
Unique device credentials/certificates
Transport
TLS
Firmware integrity
Cryptographic hash
Firmware authenticity
Digital signature
Boot
Secure boot
Downgrade protection
Firmware security/version counter
Installation
A/B or equivalent atomic update
Recovery
Automatic rollback
Authorization
Device must only receive applicable firmware
Server
Protected signing/release infrastructure
Fleet
Staged deployments
Observability
Per-device update state + telemetry
TLS protects the connection, but TLS alone isn't sufficient. Your device should independently authenticate the firmware artifact. Zephyr's OTA documentation explicitly distinguishes secure transport from signed firmware verification.
What I'd build for different platforms
MCU + RTOS
For something like STM32/nRF/ESP32:
Application
│
├── OTA client
│ ├── download
│ ├── resume
│ └── verify
│
▼
MCUboot
│
├── Slot A
└── Slot B
Zephyr + MCUboot + MCUmgr is a particularly straightforward open-source route. Zephyr also demonstrates HTTP-based FOTA where a signed image is streamed into the inactive MCUboot slot.
Embedded Linux
For Linux devices, use an A/B root filesystem rather than trying to overwrite the currently running filesystem.
For example:
eMMC / SSD
┌──────────────┐
│ bootloader │
├──────────────┤
│ rootfs A │ ← running
├──────────────┤
│ rootfs B │ ← update
├──────────────┤
│ data │
└──────────────┘
Tools such as Mender provide this model and coordinate the update, reboot, and commit/rollback process.
Build vs. use an OTA platform
You don't necessarily need to build the fleet-management backend yourself.
Managed approach
Services such as AWS IoT Device Management/Jobs provide device management, targeting, jobs, and OTA orchestration.
Open-source/platform approach
Mender provides an OTA server/client architecture and A/B update mechanisms for embedded Linux, with MCU support available through its Zephyr integration.
Then add secure boot, anti-rollback, hardware-backed device keys, delta updates, bandwidth scheduling, and more sophisticated fleet targeting as your deployment grows.
The key design principle is: assume every update can be interrupted, corrupted, incompatible, or buggy—and make sure none of those conditions can permanently brick a remotely deployed device. AWS's IoT architecture guidance likewise emphasizes resilience to network errors, corruption, and other OTA failures.
If you tell me your MCU/SoC (e.g. STM32, ESP32, nRF52), RTOS/Linux, connectivity (Wi-Fi/cellular/BLE), and approximate fleet size, I can give you a concrete OTA architecture and implementation skeleton for that platform.
Rollout protection : Store version numbers in non-volatile memory to block attackers from installing older, vulnerable firmware versions.
Backend and Server Infrastructure
Client software agent : Run a lightweight service agent on the device operating system or firmware to handle polling, downloading, and local validation tasks.
Central management dashboard : Use platform tools or third-party solutions like Mender or Memfault to group devices, target specific hardware revisions, and track campaign status.
Watch this video to understand how to design a reliable and secure server and client architecture for your fleet updates:
54s How to Make OTA Firmware Updates Reliable and Secure 10 months ago
YouTube · Digi International Inc.
Rollout and Phased Deployment
Internal testing : Push new builds to a small group of lab devices for durability and regression tests.
Staged rollout : Deploy updates to a tiny percentage of live field units first (such as one percent) before scaling up to the entire fleet over several weeks.
Automated monitoring : Track crash logs, boot loops, and connectivity rates in real time so you can pause or roll back a bad release instantly.[](https://memfault.com/blog/ota-for-iot/)
Partition the non-volatile storage (Flash) into two application slots: Slot A (Active) and Slot B (Inactive/Staging).
During an update, the bootloader downloads the new image into Slot B while Slot A continues running normally.
Once verification succeeds, the bootloader flips the active pointer to Slot B on the next reboot. If the new firmware fails to boot or crash-loops, the bootloader automatically rolls back to Slot A.
Secure the Firmware Image
Cryptographic Signing: Sign the binary using an asymmetric private key on your build server (e.g., ECDSA or RSA). Embed the public key in the device bootloader to verify integrity and authenticity before executing or applying any update.
Encryption: Encrypt the firmware binary in transit and at rest on the external flash to protect your intellectual property from reverse-engineering.
Establish Reliable Transport & Connectivity
Use lightweight, robust IoT protocols like MQTT (over TLS) or HTTPS for chunked binary downloading.
Implement resume capability (HTTP Range requests or MQTT packet offset tracking) so interrupted downloads due to poor connectivity don't restart from zero.
Set Up Backend Fleet Management Infrastructure
Device Registry & Shadow: Maintain a cloud database tracking each device's hardware version, active firmware version, and cryptographic identity (X.509 certificates).
Staged Rollouts: Deploy updates to canary groups (e.g., 1% of the fleet, then 10%, then general availability) to catch unforeseen bugs before broad deployment.
Consider leveraging managed cloud services like AWS IoT Jobs or Azure IoT Hub Device Update to handle scheduling, targeting, and monitoring out of the box.
Handle Post-Update Validation and Telemetry
Require the new firmware to report a "healthy status" back to the cloud within a specific timeout window (a "commit" phase).
If the device fails to check in or reports critical hardware faults, trigger a local software rollback to the previous working slot.
If you'd like, tell me:
What microcontroller/processor architecture (e.g., Cortex-M, ESP32, Linux-based SoC) are you using?
What connectivity do your devices have (Wi-Fi, Cellular, BLE)?
I can tailor this advice with specific framework recommendations or storage partitioning strategies.
Implementing OTA (over-the-air) firmware updates for a fleet of embedded devices is primarily a reliability, security, and fleet-management problem, not just a “download a new binary” problem. A production OTA system usually has four major pieces:
Device-side update agent
Firmware distribution backend
Secure update package format
Recovery and rollout controls
A common architecture looks like this:
CI/CD Pipeline
|
v
Build + Test Firmware
|
v
Sign Firmware Artifact
|
v
OTA Update Server
|
-------------------
| | |
Device Device Device
| | |
v v v
OTA Agent + Bootloader
Verify → Download → Install → Reboot → Confirm
A reference architecture for IoT firmware updates is also described in Internet Engineering Task Force RFC 9019, which discusses secure update components such as manifests, firmware verification, and device-side update processing.
1. Design the firmware update flow
A robust update sequence is typically:
Device checks for an update:
Periodically polls the server, or
Receives a notification through MQTT, HTTPS, etc.
Server responds with:
New firmware version
Compatibility requirements
Download URL
Cryptographic metadata
Device:
Downloads firmware
Verifies signature
Writes firmware to inactive storage
Reboots
Runs self-test
Marks update as successful
If anything fails:
Boot previous firmware
Report failure
Retry or wait for another deployment
2. Use A/B firmware partitions (recommended)
For field devices, avoid overwriting the currently running firmware.
Example flash layout:
+----------------+
| Bootloader |
+----------------+
| Firmware A | <-- currently running
+----------------+
| Firmware B | <-- new update written here
+----------------+
| Configuration |
+----------------+
| Logs / Data |
+----------------+
Update process:
Download new image into inactive slot.
Verify checksum and signature.
Mark slot B as pending.
Reboot.
Bootloader starts slot B.
Device confirms successful operation.
Slot B becomes permanent.
If the device loses power during installation, it can return to slot A.
A/B updates with rollback are commonly used in OTA systems such as Mender, where the inactive partition is updated first and committed only after a successful boot.
3. Secure the update process
Minimum security requirements:
Firmware signing
Do not trust downloaded binaries based only on HTTPS.
Typical flow:
Developer
|
| sign firmware with private key
v
Firmware package
|
| download
v
Device verifies with embedded public key
Use:
ECDSA
Ed25519
RSA (less common for constrained devices)
The private signing key should never be stored on devices.
Release 2.2.0
1% -> internal test devices
10% -> early production devices
50% -> larger fleet
100% -> full deployment
Monitor:
Boot failures
Crash rates
Battery drain
Connectivity problems
User-reported issues
6. Handle unreliable networks
Embedded devices often have:
Cellular connections
Intermittent Wi-Fi
Low bandwidth
Limited storage
Design for:
Resumable downloads
Store:
downloaded: 43%
remaining: 57%
and continue later.
Delta updates
Instead of:
Firmware 2.1.0
|
| 50 MB
v
Firmware 2.2.0
send:
Patch:
+ changed blocks only
Delta updates can reduce bandwidth usage significantly when supported.
7. Separate application updates from bootloader updates
A dangerous mistake is making the bootloader easy to replace.
A safer hierarchy:
Immutable Boot ROM
|
v
Secure Bootloader
|
v
OTA Application Firmware
|
v
User Data
The bootloader should be updated rarely and with extra safeguards.
8. Choose an OTA framework or build your own
Common approaches:
Embedded Linux devices
Options include:
Mender — client/server OTA architecture with fleet deployment management and A/B update support.
RAUC
SWUpdate
Microcontrollers
Typical stack:
MCUboot
+
RTOS OTA agent
+
Cloud update service
For example, Mender documents MCU OTA integration using Zephyr and MCUboot with A/B-style firmware handling.
9. Example implementation stack
For a fleet of STM32/ESP32-class devices:
Device
MCUboot bootloader
Dual firmware slots
Secure element for keys
HTTPS/MQTT client
OTA manager task
Backend
Device registry
Firmware artifact storage
Deployment scheduler
Metrics dashboard
CI/CD
Build firmware
Run hardware tests
Generate manifest
Sign artifact
Publish release
10. Test failure scenarios
Before deploying, test:
Scenario
Expected behavior
Power loss during download
Resume/retry
Power loss during install
Boot old firmware
Corrupt firmware
Reject
Invalid signature
Reject
Firmware crash on boot
Roll back
Network disappears
Retry later
A practical production checklist:
✅ Signed firmware images
✅ Secure boot verification
✅ A/B partitions or equivalent rollback mechanism
✅ Device authentication
✅ Version and downgrade protection
✅ Staged deployments
✅ Failure telemetry
✅ Recovery path for bricked devices
✅ Automated build/sign/release pipeline
The exact implementation depends heavily on whether your fleet uses bare-metal MCUs (STM32, ESP32, nRF52, etc.), RTOS devices (Zephyr/FreeRTOS), or embedded Linux (Yocto, Buildroot, Debian).
A production OTA system is best thought of as a secure deployment pipeline plus a fail-safe boot/update mechanism, not simply “download a new .bin file.”
A solid architecture looks like this:
Developer
│
▼
CI/CD ──► Build firmware ──► Sign artifact
│
▼
OTA backend / CDN
│
deployment + targeting
│
┌───────────────┴───────────────┐
▼ ▼
Device A Device B
OTA client OTA client
│ │
TLS/auth TLS/auth
│ │
▼ ▼
Bootloader Bootloader
A/B slots A/B slots
┌──────┐ ┌──────┐
│ FW A │ │ FW A │
├──────┤ ├──────┤
│ FW B │ │ FW B │
└──────┘ └──────┘
The device normally executes A. The OTA client downloads the new image into B, verifies it, marks B as the next boot target, and reboots.
On the first boot, the new firmware must prove that it successfully initialized. Only then does the bootloader permanently commit B. Otherwise, the bootloader returns to A.
This A/B approach protects against failures such as power loss during installation or a firmware image that boots incorrectly. It's a common pattern in robust OTA systems.
For embedded Linux, the same concept is commonly implemented with two root filesystem partitions. Mender, for example, writes the new image to the inactive partition and rolls back if the new system doesn't successfully boot and commit.
2. Cryptographically sign every firmware image
Don't rely on TLS alone.
You want two separate protections:
TLS protects the connection while downloading.
Firmware signatures establish that the binary itself was produced by you and hasn't been modified.
Keep the signing private key out of ordinary developer machines. Ideally, signing happens through a controlled CI/CD process backed by an HSM or equivalent key-management system.
The device should contain only the public verification key or certificate chain. Hardware-backed key storage can provide another layer of protection.
Also include:
Firmware version
Hardware/model identifier
Image size
Cryptographic hash
Signature
Minimum bootloader version
Optional minimum hardware revision
Release metadata
3. Prevent firmware downgrade attacks
Suppose an attacker obtains a perfectly valid firmware image from six months ago that contains a vulnerability.
A valid signature doesn't make that image safe.
Have the bootloader enforce a monotonic version/security counter:
X.509 device certificates are one common approach for IoT fleets. AWS's guidance similarly recommends unique device identities and credentials rather than shared fleet credentials.
Ideally, private device keys are generated/stored in a secure element, TPM, or other hardware-backed storage when your hardware supports it.
5. Separate the OTA client from the bootloader
A useful division is:
OTA client
Contacts server
Authenticates device
Determines whether an update exists
Downloads it
Resumes interrupted downloads
Verifies metadata/hash
Places image into inactive slot
Tells bootloader to attempt update
Reports success/failure
Bootloader
Validates firmware signature
Checks compatibility/version policy
Selects boot slot
Tracks boot attempts
Rolls back failed images
That separation means a compromised or buggy application doesn't get unrestricted authority to replace the bootloader's security decisions.
6. Design for unreliable networks
Assume the connection will disappear halfway through the download.
Your update protocol should support:
HTTP range/resumable downloads or equivalent
Chunked downloads
Hash/checksum validation
Retries with exponential backoff
Power-loss recovery
Persistent download state
Sufficient free flash/storage
Verification before activation
Don't make an interrupted download equivalent to a failed firmware installation.
For cellular devices in particular, also consider bandwidth and data costs. Full-image updates are simple and robust, while delta updates can substantially reduce bandwidth at the cost of additional complexity.
7. Don't update the whole fleet simultaneously
Your backend should support staged deployments.
For example:
Firmware 2.7.0
└── Internal test devices 20
│
▼
Canary fleet 100
│
▼
1% of production
│
▼
10% of production
│
▼
25%
│
▼
100%
At each stage, monitor:
Download failures
Installation failures
Boot failures
Rollback rate
Device connectivity
Application health
Crash/reset rates
Battery consumption
Relevant application-specific metrics
Automatically pause the rollout if failure rates exceed your thresholds.
Fleet deployment systems such as AWS IoT Jobs explicitly support controlled deployment/rollback patterns, while OTA guidance recommends gradual rollouts rather than updating every device simultaneously.
8. Use device groups and compatibility constraints
Don't send one generic firmware to every device.
Your update manifest might look conceptually like:
model = sensor
hardware_revision = C
region = US
current_version < 2.7.0
This becomes particularly important when you have multiple MCU types, board revisions, bootloader versions, or product generations.
9. Keep application data separate from firmware
Don't overwrite configuration and user/device state when replacing firmware.
For example:
Flash
├── Bootloader
├── Firmware A
├── Firmware B
├── Device identity
└── Persistent data
├── configuration
├── calibration
└── application state
Your firmware update should be able to replace either firmware slot without destroying persistent data.
For Linux systems, this separation is also important because replacing an entire root filesystem can otherwise remove files that applications expect to persist.
10. Pick the implementation according to your hardware
MCU / RTOS
If you're using something like Zephyr, a strong starting point is MCUboot plus an OTA management layer. MCUboot provides image verification and A/B-style slot management; Mender, for example, integrates its MCU client with Zephyr and MCUboot for atomic OTA updates and rollback.
Embedded Linux
For Linux devices, an image-based A/B system is usually attractive.
Options include:
Mender
RAUC
SWUpdate
OSTree-based systems
A custom U-Boot + A/B implementation
Mender, for example, provides a device client and server architecture with A/B root filesystem updates and rollback.
Cloud backend
You can either build the control plane yourself or use an OTA fleet-management service.
A managed architecture might be:
CI/CD
│
├── Build
├── Test
├── Sign
└── Publish
│
▼
OTA service
│
┌────┴────┐
│ │
device device
AWS IoT Jobs is one example of a service providing fleet targeting and OTA job management.
Mender is another example, with a server/client architecture and support for both embedded Linux and, through its MCU integration, constrained microcontrollers.
A practical implementation plan
I'd build it in this order:
Bootloader
Signature verification
A/B slots
Version protection
Boot-attempt counter
Automatic rollback
Local updater
Download firmware
Resume interrupted downloads
Validate hash/signature
Write inactive slot
Request reboot
Report result
Device identity
Unique device credentials
TLS
Secure credential storage
Artifact pipeline
Reproducible firmware build
Automated tests
Firmware signing
Artifact repository
OTA backend
Device inventory
Firmware versions
Device groups
Deployment jobs
Status reporting
Staged rollout
Test → canary → percentage rollout → full fleet
Automatic pause/rollback criteria
Observability
Update state per device
Failure reason
Current/previous firmware
Boot failures
Rollbacks
Connectivity
The key design principle
Never make “downloaded successfully” mean “updated successfully.”
A robust lifecycle is:
AVAILABLE
↓
DOWNLOADING
↓
DOWNLOADED
↓
SIGNATURE VERIFIED
↓
INSTALLED IN INACTIVE SLOT
↓
PENDING REBOOT
↓
BOOTING NEW IMAGE
↓
HEALTH CHECK
├── FAIL → ROLLBACK
│
└── PASS → COMMIT
That state machine, combined with cryptographic verification, A/B storage, rollback, unique device identity, and staged fleet deployment, gives you the foundation of a production-grade OTA system.
If you tell me your MCU/SoC (e.g. ESP32, STM32, nRF52, i.MX), RTOS/Linux choice, connectivity (Wi-Fi/cellular), and approximate fleet size, I can lay out a concrete OTA architecture and flash partition map for it.
Implementing over-the-air (OTA) firmware updates for a fleet of embedded devices requires a robust, secure, and fault-tolerant architecture. If an update fails mid-way, you don't want a fleet of expensive, unrecoverable "brick" devices in the field.
Here is a clear, structured roadmap to building a reliable OTA pipeline:
Hardware & Memory Architecture (Dual-Bank Flash)
Dual-Bank (A/B) Partitioning : Divide your non-volatile storage (Flash) into two separate application partitions: Bank A (Active/Running) and Bank B (Inactive/Staging). The bootloader boots from Bank A while the new firmware downloads safely into Bank B.
The Bootloader : Keep your primary bootloader small, secure, and rarely changed. It is responsible for verifying the integrity of the newly flashed image, swapping the active pointer, and handling rollbacks if the new firmware crashes.
Fallback/Rollback Mechanism : If the new firmware fails its health check or fails to report a "success" status to the bootloader within a watchdog timeout window, the bootloader automatically reverts to the previous working image (Bank A).
Security & Cryptography
Cryptographic Signing : Never push unsigned binaries. Sign your firmware images on your build server using a private key (e.g., using Ed25519 or RSA-3072). The embedded device verifies the signature with an embedded public key before applying the update.
Transport Security : Use strict TLS (1.3) for downloading images over Wi-Fi, Cellular, or Ethernet to prevent man-in-the-middle tampering or snooping.
Encrypted Images : If your firmware contains proprietary algorithms or sensitive keys, encrypt the binary payload itself and decrypt it on-the-fly or inside a secure element/microcontroller flash controller.
Backend & Fleet Management Infrastructure
Device Registry & Metadata : Maintain a database of your fleet tracking each device's hardware revision, current firmware version, and cryptographic identifier (like a UUID or hardware-bound certificate).
Delta Updates : For constrained bandwidth (like Cellular/NB-IoT), generate binary diffs (using tools like bsdiff) so devices download only the changed bytes rather than a full monolithic image, saving data and time.
Phased Rollouts (Canary Deployments) : Avoid updating the entire fleet at once. Push updates to a 1% canary group, monitor telemetry for errors or crash loops, and scale up to 10%, 50%, and 100% progressively.
Open-Source & Managed Ecosystem Tools
MCUboot : A secure bootloader for 32-bit microcontrollers that natively supports dual-image swappable slots and signature verification.
AWS IoT Jobs / Azure Device Update : Cloud-managed frameworks that handle device grouping, rollout scheduling, and security for connected fleets.
Mender or Balena : End-to-end open-source and commercial OTA update software specifically engineered for Linux-based or RTOS embedded edge devices.
To help tailor this design, let me know:
What microcontroller or processor family (e.g., ESP32, STM32, ARM Cortex-A Linux) are you using?
What is your connectivity medium (Wi-Fi, Cellular, LoRaWAN, Ethernet)?
To build a production-grade OTA pipeline, you must structure the implementation across distinct hardware, software, and cloud layers.
Core Architecture Components
A/B (Dual-Bank) Partitioning : Split your non-volatile flash memory into two separate application slots (Slot A and Slot B). While the device runs actively on Slot A, the incoming new firmware downloads safely into Slot B. Once verified, the bootloader switches execution to Slot B, preventing a bricked device if a power loss occurs mid-download.[](https://mender.io/resources/reports-and-guides/ota-updates-best-practices)
Transport and Device Management : Use lightweight IoT communication protocols like MQTT, HTTPS, or CoAP to stream packages. You can build a custom server or integrate with commercial and open-source device management tools like Mender or Eclipse hawkBit to handle campaign rollouts.[](https://witekio.com/embedded-software/embedded-linux/ota-update/)
Implementation Workflow
Step
Phase
Action & Engineering Requirement
1
Partitioning
Configure the memory map in your linker script to reserve space for Bootloader, Application A, Application B, and non-volatile configuration storage.
2
Transport
Set up an agent daemon on the device to securely poll or receive notification cues from your server regarding a pending manifest update.
3
Verification
Download the binary chunk-by-chunk, calculate a local SHA-256 hash, and verify the cryptographic signature against the embedded public key.
4
Activation
Write the validated payload to the inactive flash bank, update the bootloader metadata flag to swap boot targets, and trigger a controlled software reset.
5
Validation
Run a post-installation health check on the new firmware. If the app fails to ping the watchdog or confirm operational status within a set window, force a rollback.
Best Practices for Fleet Management
Implement Atomic Updates : Ensure updates either succeed entirely or abort cleanly without leaving partial, corrupted binaries in the active execution path.
Staged Rollouts : Never push a new firmware build to your entire fleet at once. Target a canary group (1% to 5% of devices), monitor telemetry and error logs for anomalies, and only then proceed with a wide release.
A robust OTA system for an embedded fleet should be designed as secure boot + signed firmware + fail-safe installation + controlled fleet rollout, rather than simply “download a binary and flash it.”
Recommended architecture
┌─────────────────────┐
│ Firmware CI/CD │
│ build + test + sign │
└──────────┬──────────┘
│
signed image
│
┌──────────▼──────────┐
│ Firmware repository │
│ object storage/CDN │
└──────────┬──────────┘
│ HTTPS
│
┌────────────────────▼────────────────────┐
│ OTA service │
│ device inventory / jobs / rollout │
└────────────────────┬────────────────────┘
│ MQTT/HTTPS
┌─────────────┴─────────────┐
│ │
┌─────▼─────┐ ┌─────▼─────┐
│ Device A │ ... │ Device N │
│ OTA agent │ │ OTA agent │
│ bootloader│ │ bootloader│
└───────────┘ └───────────┘
1. Put a secure bootloader underneath the application
The bootloader should verify that an image is:
cryptographically authentic
intact
compatible with the hardware
sufficiently new
authorized to run
For MCU-class devices, MCUboot is one established option. It supports signed images and upgrade/rollback mechanisms, including a test boot followed by confirmation of the new firmware.
A typical flash layout is:
+-----------------------+
| Bootloader | <-- immutable/protected
+-----------------------+
| Application slot A | <-- currently running
+-----------------------+
| Application slot B | <-- downloaded update
+-----------------------+
| Persistent data |
+-----------------------+
This A/B scheme is extremely valuable. Don't overwrite the only known-good application image while performing an OTA update.
2. Sign firmware in CI/CD
Your build pipeline should produce something like:
Then sign the image/metadata with a release signing key.
The device should have only the public verification key (or a chain of trust); the private signing key should never exist on the device.
Also implement anti-rollback. Otherwise an attacker who obtains an old but validly signed vulnerable firmware image could potentially downgrade a device. MCUboot, for example, supports version/security-counter-based downgrade prevention.
3. Have the device ask whether an update exists
Don't necessarily push a several-megabyte binary directly over your command channel.
The device then downloads the image, preferably over HTTPS.
For constrained devices, MQTT-based block transfer can also make sense. AWS's OTA implementation, for example, supports HTTP and MQTT delivery and separates notification, downloading, cryptographic verification, and installation.
4. Download into the inactive slot
The device should:
Check that enough storage is available.
Download into slot B.
Verify the complete image hash.
Verify the firmware signature.
Verify hardware/product compatibility.
Verify version/security counter.
Mark slot B as a pending/test image.
Reboot.
Critically, don't erase slot A until the new firmware has successfully booted.
5. Make the first boot a trial
The bootloader/application state machine should look approximately like:
update available
│
▼
Download image
│
▼
Verify image
│
▼
Boot new image
│
┌─────┴─────┐
│ │
self-test OK crash/watchdog
│ │
▼ ▼
CONFIRM ROLLBACK
│
▼
normal boot
The application should confirm the new firmware only after passing meaningful health checks, such as:
initialization succeeds
flash/filesystem is healthy
communications work
critical peripherals respond
configuration can be loaded
watchdog operates normally
MCUboot explicitly supports this test/confirm/revert pattern.
6. Treat fleet deployment separately from firmware delivery
This is where many OTA implementations become dangerous.
Cloud fleet-management systems such as AWS IoT Device Management provide rollout controls, failure thresholds, device groups, and monitoring for this purpose.
You can store a small download-progress record in persistent storage.
For cellular devices especially, also consider:
bandwidth limits
battery state
data costs
update windows
maximum retry count
8. Separate firmware identity from device identity
Every device should have a unique cryptographic identity, for example:
device certificate/private key
↓
authenticated
↓
OTA service
The OTA service should know:
device ID
hardware revision
current firmware
region
deployment group
last successful update
last failed update
That lets you say:
Deploy firmware 2.7.4 only to sensor-v3, hardware revisions C/D, excluding devices currently reporting low battery.
This is much safer than broadcasting a firmware URL to every device.
9. Design for power loss
Assume the device loses power at every possible point:
during download
during flash write
after flash write
during reboot
during first boot
during confirmation
Your state machine should still result in either:
known-good firmware
or
new firmware + ability to revert
Never require the network to recover a device after a failed update. The recovery mechanism must be local to the device.
10. Keep application data separate from firmware
Don't casually erase:
configuration
calibration
device identity
keys/certificates
user data
when installing firmware.
Use separate flash partitions or a carefully designed migration mechanism:
Bootloader
Firmware A
Firmware B
Device credentials
Configuration
Application data
OTA metadata
If firmware 2.7 changes the configuration schema, make migrations explicit and preferably reversible.
A practical technology stack
For a typical MCU product, one reasonable stack is:
Layer
Example
Bootloader
MCUboot
RTOS
Zephyr / FreeRTOS
Transport
HTTPS, optionally MQTT
Firmware storage
S3/object storage + CDN
Fleet management
AWS IoT Jobs or equivalent
MCUboot is OS-independent and supports several embedded operating systems and MCU platforms.
If you're already using AWS IoT, AWS's OTA Update Manager can create OTA updates targeting device groups, deliver via MQTT/HTTP, and integrate signing and IoT Jobs.
The key security rule
The most important principle is:
Never trust the update server alone. The device itself must cryptographically decide whether an image is allowed to execute.
Even if your cloud account, CDN, network, or update metadata is compromised, an attacker should not be able to make the device execute an unsigned or unauthorized firmware image.
If you tell me your MCU/SoC (e.g. ESP32, STM32, nRF52/nRF53), RTOS/Linux, connectivity (Wi-Fi/cellular/LoRaWAN), and approximate fleet size, I can lay out a concrete flash layout, bootloader state machine, signing scheme, cloud architecture, and implementation skeleton for that platform.
A production OTA system is best designed as a secure update pipeline + a fail-safe boot/update mechanism + fleet rollout controls. The exact implementation depends heavily on whether your devices run embedded Linux or a microcontroller RTOS.
A service such as aws.amazon.com provides the fleet-management/job portion, while alternatives such as Mender provide both server and device-side OTA infrastructure. AWS IoT Jobs, for example, can send jobs instructing devices to download/install firmware and report their status.
2. Make the firmware cryptographically signed
Don't rely on HTTPS alone.
Your release pipeline should produce something like:
Verify the manufacturer's digital signature using a public key embedded/protected on the device.
Check hardware compatibility.
Check that the version/security counter is acceptable.
Only then install it.
For example, MCUboot supports signed images and downgrade prevention using version/security-counter mechanisms.
Keep the signing private key off the device and preferably out of ordinary developer workstations. Your CI/CD release process should be the only thing authorized to produce production-signed firmware.
3. Use A/B firmware partitions
This is probably the most important reliability feature.
For a Linux device:
Flash
┌─────────────────────┐
│ Bootloader │
├─────────────────────┤
│ Root filesystem A │ ← currently running
├─────────────────────┤
│ Root filesystem B │ ← install update here
├─────────────────────┤
│ Persistent data │
└─────────────────────┘
The device downloads the new image into the inactive partition. It doesn't overwrite the currently working firmware.
Then:
A running
↓
download firmware
↓
verify signature/hash
↓
install into B
↓
boot B
↓
health check
↓
mark B good
If power disappears during the download or installation, A remains intact.
If B boots but crashes repeatedly, the bootloader should automatically return to A.
This is the model used by systems such as Mender and RAUC; Mender explicitly uses redundant A/B partitions for fail-safe OS updates, while RAUC supports atomic redundant-system updates and cryptographic bundle verification.
For an MCU, a bootloader such as MCUboot can provide the equivalent two-slot mechanism. Mender's Zephyr integration, for example, combines a device-side client with MCUboot's two-slot update mechanism and rollback behavior.
4. Separate "download" from "activate"
Your OTA agent should behave roughly like this:
if (!update_available())
return;
download_to_inactive_slot();
if (!verify_hash())
fail();
if (!verify_signature())
fail();
if (!compatible_with_hardware())
fail();
if (!version_is_allowed())
fail();
mark_slot_pending();
reboot();
Then automatically stop the rollout if failure rates exceed your threshold.
AWS IoT Device Management, for example, supports fleet grouping, rollout velocity and failure thresholds for OTA deployments.
6. Give every device useful metadata
Your OTA service should know at least:
device_id
hardware_model
hardware_revision
current_firmware
bootloader_version
region
environment
last_seen
battery_level
update_status
This lets you target:
hardware_model == "sensor-v2"
AND hardware_revision == "B"
AND current_firmware < "3.7.2"
AND environment == "production"
rather than accidentally sending a firmware image intended for one hardware revision to the entire fleet.
AWS's continuous OTA mechanism, for example, supports targeting devices using metadata attributes.
7. Design for bad networks
The update process should tolerate:
Wi-Fi/cellular disconnections
device power loss
partial downloads
server failures
intermittent connectivity
devices being offline for weeks
Useful techniques include:
resumable downloads
chunked downloads
checksums
download-to-inactive-slot
retry with exponential backoff
randomized polling/jitter
CDN/object storage for firmware
update bandwidth limits
persistent update state
Don't have 50,000 devices all wake up at exactly midnight and request a 20 MB image.
8. Protect against rollback attacks
There's an important distinction between:
"Rollback automatically if the new firmware crashes."
and:
"Allow anyone to install an old, vulnerable firmware."
You want the first but generally not the second.
Use a monotonically increasing security counter or equivalent anti-downgrade mechanism. MCUboot, for example, supports security counters for preventing installation of images below the trusted version.
Ideally you have a protected recovery mechanism—such as a factory image, ROM bootloader, hardware recovery interface, or redundant bootloader strategy—so a failed bootloader update doesn't permanently brick the device.
For embedded Linux, frameworks such as RAUC and Mender can handle substantial portions of this update architecture.
10. Choose the implementation based on your device
Embedded Linux
A practical stack could be:
Yocto/Buildroot
+
U-Boot
+
RAUC or Mender
+
HTTPS/object storage
+
OTA management server
Mender is particularly oriented toward fleet management and supports managed deployments, while RAUC is a lightweight update client/bundle system.
MCU / RTOS
A typical architecture is:
FreeRTOS / Zephyr
+
MCUboot
+
A/B flash slots
+
HTTPS/MQTT
+
OTA service
For MCUboot-based systems, the bootloader performs image validation and manages the slot transition/rollback.
Cloud-managed fleet
If you're already heavily invested in AWS, a reasonable architecture is:
CI/CD
↓
Code signing
↓
S3
↓
AWS IoT Jobs
↓
Device OTA agent
↓
A/B bootloader
AWS's OTA agent model explicitly expects the device to download the firmware, verify its digital signature, install it, and report the job result.
11. A good minimum production design
If I were designing a new fleet today, I'd make these requirements non-negotiable:
Component
Requirement
Transport
TLS
Firmware authenticity
Digital signature
Integrity
Cryptographic hash
Storage
A/B slots
Boot
Secure/verified boot
Failure handling
Automatic rollback
Downgrade protection
The key principle is: an OTA system shouldn't merely make firmware downloadable; it should make an interrupted, malicious, incompatible, or broken update fail safely.
If you tell me your MCU/SoC (e.g. ESP32, STM32, nRF52, Raspberry Pi), OS/RTOS, connectivity (Wi-Fi/cellular/etc.), approximate fleet size, and whether you have a cloud backend, I can sketch a concrete architecture and implementation—including partition layout, bootloader flow, manifest format, and device-side OTA code.
Cryptographic Verification : Sign every firmware image using private-public key cryptography (such as Ed25519 or ECDSA) during your CI/CD build process. The embedded device must use a hardcoded public key—often stored in a hardware Root of Trust or secure element—to verify the signature before writing or booting the image.[](https://memfault.com/blog/ota-for-iot/)
Build and Sign : Compile your application binary and generate a cryptographic signature hash (e.g., SHA-256) of the image.
Staged Upload : Push the validated artifact package to your secure server repository or OTA orchestration platform.
Notification and Download : The device client queries the server (via scheduled polling or broker alert) and downloads the update into the inactive flash bank over an encrypted TLS connection.
Integrity Check : The device validates the file checksum and verifies the digital signature against the stored public key.