The Amazon Web Services firmware over-the-air (AWS FOTA) sample shows how to perform an over-the-air firmware update of an nRF9160 device using MQTT and HTTP. It is similar to the nRF9160: HTTP application update, except that the firmware download is triggered through an AWS IoT job.


The sample supports the following development kit:

Hardware platforms


Board name

Build target

nRF9160 DK




The sample requires an AWS account with access to Simple Storage Service (S3) and the IoT Core service.

When built for an _ns build target, the sample is configured to compile and run as a non-secure application. Therefore, it automatically includes Trusted Firmware-M that prepares the required peripherals and secure services to be available for the application.

You can also configure it to use the Secure Partition Manager.


The sample connects to the configured AWS IoT MQTT broker and subscribes to several topics related to AWS IoT jobs. When an update job is created on the AWS IoT service, the sample receives a notification through MQTT.

Triggered by the notification, the sample retrieves the metadata for the update job over MQTT. This metadata contains the location of the new firmware image (which is generated when building the sample, but you must upload it to a server). The sample then retrieves the firmware image over HTTP and replaces the current firmware with the downloaded firmware.

See AWS FOTA for information about the download procedure. The AWS IoT Developer Guide contains all required information about the Amazon Web Services IoT service.


A file server instance that hosts the new firmware image is required for this sample. You can set up and use your own AWS S3 server bucket to host the firmware described in the Setting up an AWS S3 bucket section.


See Configuring your application for information about how to permanently or temporarily change the configuration.


Complete the steps in this section to configure the sample for use.

Create a thing in AWS IoT

Before you can run this sample, you must create a thing for your development kit in AWS IoT so that AWS knows about your kit. This thing must be connected to a security policy. For testing, you can use a permissive policy, but make sure to update the policy to be more restrictive before you go into production. See AWS IoT Developer Guide: Basic Policy Variables and AWS IoT Developer Guide: Security Best Practices for more information about policies.

To create a thing for your kit:

  1. Log on to the AWS IoT console.

  2. Go to Secure > Policies and select Create a policy.

  3. Enter a name and define your policy. For testing purposes, you can use the following policy (switch to Advanced mode to copy and paste it):

       "Version": "2012-10-17",
       "Statement": [
             "Effect": "Allow",
             "Action": "iot:*",
             "Resource": "*"
  4. Go to Manage > Things and select Register a thing or Create (depending on whether you already have a thing registered).

  5. Select Create a single thing.

  6. Enter a name. The default name used by the sample is your_client_id. If you choose a different name, make sure to configure a custom client ID in the sample before you build it.

  7. Accept the defaults and continue to the next step.

  8. Select Create certificate to generate new certificates. Alternatively, you can use existing certificates. In this case, follow the instructions in AWS IoT.

  9. Download the certificates for later use. You need the thing certificate (*-certificate.pem.crt), the private key (*.private.pem.key), and the root CA (choose the Amazon Root CA 1, AmazonRootCA1.pem).

  10. Click Activate to activate the certificates.

  11. Click Attach a policy to continue to the next step.

  12. Select the policy that you created in step 3 and click Register Thing.

Update the certificates

The certificates that you created or added for your thing in AWS IoT must be stored on your kit so that it can connect to AWS IoT.

Use LTE Link Monitor to write the certificates to the kit. This application, which is part of nRF Connect for Desktop, provides a certificate manager that you can use to store the certificates on your kit.


The LTE Link Monitor overwrites the certificates stored on the device with the given security tag number. Therefore, make sure that you are using the correct security tag.

Use LTE Link Monitor to write the certificates to the kit:

  1. Make sure that you have the AT client sample programmed on your kit.

  2. Put the modem in offline state.

  3. Paste the three certificates into the respective fields.

  4. Choose a security tag.

  5. Click Update certificates.

  6. Before programming the sample, make sure to configure the security tag to the one that you chose.

Setting up an AWS S3 bucket

The firmware files for download must be stored in a bucket on an AWS S3 server. To do this, set up your own bucket.

When setting up your own bucket, make sure to configure the permissions as shown in the following screenshot:

Bucket permissions in AWS S3

To update the permissions for an existing bucket, select your bucket and navigate to Permissions > Block public access.

In addition to the permissions, you must configure a bucket policy. To determine a suitable security scheme for your application, see AWS S3 Developer Guide: Using Bucket Policies and User Policies and AWS S3 Developer Guide: Bucket Policy Examples. To configure the policy, select your bucket and navigate to Permissions > Bucket Policy.

For testing purposes, you can use the following, very permissive, bucket policy (replace bucket_name with the name of your bucket):

{    "Version": "2012-10-17",
     "Statement": [
             "Effect": "Allow",
             "Principal": "*",
             "Action": "s3:GetObject",
             "Resource": "arn:aws:s3:::bucket_name/*"

Configuration options

Before you build the sample, check and update the following configuration options:

CONFIG_APP_VERSION - Application version

The version string is printed when the sample starts. Use this information to verify that the FOTA update worked.

CONFIG_CERT_SEC_TAG - Security tag for TLS credentials

By default, the sample uses the certificates that are stored with the security tag for nRF Cloud. To use different certificates, configure a different security tag. If you used LTE Link Monitor to store the certificates, make sure to configure the security tag to the same that you used to store them.


By default, the sample uses nRF Cloud’s MQTT broker. Change this value to AWS IoT’s MQTT broker. To find the address of the AWS IoT MQTT broker, open the AWS IoT console, go to Settings and read the endpoint under Device data endpoint.


The client ID links your kit to the thing in AWS IoT. By default, the client ID is your_client_id. If you chose a different name for your thing in AWS IoT, check this option and specify the AWS IoT thing name as client ID.

For all other values, use the default values unless you are using a custom MQTT server.

Building and running

This sample can be found under samples/nrf9160/aws_fota in the nRF Connect SDK folder structure.

When built as a non-secure firmware image for the _ns build target, the sample automatically includes the Trusted Firmware-M (TF-M). You can configure it to use the Secure Partition Manager instead of TF-M.

See Building and programming an application for information about how to build and program the application.


After programming the sample to your development kit, test it by performing the following steps:

  1. Connect to the kit with a terminal emulator (for example, PuTTY). See How to connect with PuTTY for the required settings.

  2. Reset the kit.

  3. Confirm that the sample prints the configured application version and connects to AWS IoT. You should see output like the following:

    ***** Booting Zephyr OS build v1.14.99-ncs3-snapshot2-1281-g40b430ba977c *****
    The MQTT AWS Jobs FOTA Sample, version: v1.0.0
    LTE Link Connecting ...
    LTE Link Connected!
    IPv4 Address
    client_id: nrf-aws-fota
    [mqtt_evt_handler:129] MQTT client connected!
    [00:00:14.106,140] <inf> aws_jobs: Subscribe: $aws/things/nrf-aws-fota/jobs/notify-next
  4. Log on to the AWS IoT console, go to Manage -> Things, and select your thing.

  5. In the Testing, change the application version. Then rebuild the application, but do not program it.

  6. Go to AWS S3 console and sign in.

  7. Go to the bucket you have created.

  8. Click Upload and select the file app_update.bin (located in the zephyr subfolder of your build directory).

  9. Click the file you uploaded in the bucket and check the Object URL field to find the download URL for the file.

  10. Create a job document (a text file) with the following content, replacing host_url with the server part of the URL that you created (for example, and file_path with the path and file name (for example, nordic-firmware-files/app_update.bin):

      "operation": "app_fw_update",
      "fwversion": "v1.0.2",
      "size": 181124,
      "location": {
        "protocol": "http:",
        "host": "host_url",
        "path": "file_path"

    See AWS IoT Developer Guide: Jobs for more information about AWS jobs.

  11. Log on to the AWS S3 console.

  12. Select the bucket, click Upload, and select your job document. Use the default settings when uploading the file.

  13. Log on to the AWS IoT console, go to Manage > Jobs, and select Create a job.

  14. Click Create custom job and enter a unique job ID. Select your device and the job file that you uploaded to AWS S3. Use the default settings for all other options.

  15. Since the sample is configured to subscribe to the app_fw_update job topic, it picks up the job automatically. This can take several minutes. Select the job in AWS IoT to confirm that it is in progress. Note that it might show as in progress on the overview, while it is actually queued.

  16. In the terminal emulator, observe that the new firmware image is downloaded and installed. You should see output similar to the following:

    [00:02:03.748,931] <inf> download_client: Downloaded 135168/201232 bytes (67%)
    [00:02:03.794,494] <inf> fota_flash_block: Erasing sector at offset 0x00021000
    [00:02:04.893,188] <inf> download_client: Downloaded 139264/201232 bytes (69%)
    [00:02:04.938,720] <inf> fota_flash_block: Erasing sector at offset 0x00022000
    [00:02:05.933,013] <inf> download_client: Downloaded 143360/201232 bytes (71%)
    [00:02:05.978,546] <inf> fota_flash_block: Erasing sector at offset 0x00023000
    [00:05:20.585,266] <inf> aws_fota: Firmware download completed
  17. When the kit resets, observe that the sample prints the new application version.

  18. Log on to the AWS IoT console, go to Manage > Things, and select your thing.

  19. Go to Shadow and confirm that the application version has updated.


ERROR: mqtt_connect -ECONNREFUSED:

Error -ECONNREFUSED (“Connection refused”) may indicate an error with the configured certificates.

Content range is not defined:

If you host the firmware image on a different server than in an S3 bucket, this error indicates that the Content-Range field is missing in the HTTP GET header. To fix this problem, configure the host server to provide this field. If you are using an S3 bucket, make sure that you have configured it as described in Setting up an AWS S3 bucket. Also, confirm that your file is available from the browser without being logged into your AWS account.


This sample uses the following nRF Connect SDK libraries:

It uses the following sdk-nrfxlib library:

It uses the following Zephyr library:

In addition, it uses the following secure firmware component: