Add a license (disconnected)

Overview

This guide shows you how to add a license to NGINX Instance Manager in a disconnected (offline) environment. In this setup, systems don’t have internet access. You’ll download and apply your subscription’s JSON Web Token (JWT) license, then verify your entitlements with F5.

You can use tools like curl or Postman to interact with the NGINX Instance Manager REST API. The API URL is https://<NIM-FQDN>/api/[nim|platform]/<API_VERSION>, and each request requires authentication. For more details on authentication options, see the API Overview.

Before you begin

Set the operation mode to disconnected

To configure NGINX Instance Manager for a disconnected environment, you need to set the mode_of_operation to disconnected in the configuration file.

  1. Open the /etc/nms/nms.conf file and add the following in the integrations:license section:

    yaml
    integrations:
        license:
            mode_of_operation: disconnected
  2. Restart NGINX Instance Manager:

    sudo systemctl restart nms

Download the JWT license from MyF5

  1. Log in to MyF5.
  2. Go to My Products & Plans > Subscriptions to see your active subscriptions.
  3. Find your NGINX subscription, and select the Subscription ID for details.
  4. Download the JSON Web Token file from the subscription page.

Add license and submit initial usage report

To add a license and submit the initial usage report in a disconnected environment, use the provided license_usage_offline.sh script. Run this script on a system that can access NGINX Instance Manager and connect to https://product.apis.f5.com/ on port 443. Replace each placeholder with your specific values.

Important: The script to add a license won’t work if a license has already been added.


  1. Download license_usage_offline.sh.

  2. Run the following command to allow the script to run:

    chmod +x <path-to-script>/license_usage_offline.sh
  3. Run the script. Replace each placeholder with your specific values:

    bash
    ./license_usage_offline.sh \
      -j <license-filename>.jwt \
      -i <NIM-IP-address> \
      -u admin \
      -p <password> \
      -s initial

    This command adds the license, downloads the initial usage report (report.zip), submits the report to F5 for acknowledgment, and uploads the acknowledgment back to NGINX Instance Manager.

Full license_usage_offline.sh script
shell
#!/bin/bash

# Enable strict mode for better error handling
set -euo pipefail
IFS=$'\n\t'

# Debug mode
if [[ "${DEBUG:-false}" == "true" ]]; then
  set -x  # Enable command tracing
  echo "Debug mode enabled"
  echo "Running in directory: $(pwd)"
  echo "Script arguments: $*"
  env | grep -E 'JWT_FILE|NIM_IP|USERNAME|PASSWORD|USE_CASE'
fi

# Set timeouts for operations
CURL_TIMEOUT=${CURL_TIMEOUT:-30}
API_POLL_TIMEOUT=${API_POLL_TIMEOUT:-60}

# Function to log with timestamp
log() {
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}

log "Script started"

# Function to display usage
usage() {
  echo "Usage: $0 -j <JWT file> -i <NIM IP> -u <username> -p <password> -s <initial|telemetry>"
  echo
  echo "Options:"
  echo "  -j <JWT file>     Path to the JWT (JSON Web Token) file used for authentication."
  echo "  -i <NIM IP>       IP address of the NIM (NGINX Instance Manager) to connect to."
  echo "  -u <username>     Username for login/authentication to NIM (NGINX Instance Manager)."
  echo "  -p <password>     Password corresponding to the username for NIM (NGINX Instance Manager) authentication."
  echo "  -s <mode>         Script execution mode. One of the following:"
  echo "                      initial       - Perform Initial License Activation"
  echo "                      telemetry     - Perform telemetry submission: download usage report from NGINX Instance Manager and submit to F5."
  exit 1
}

# Parse command-line arguments
while getopts ":j:i:u:p:s:" opt; do
  case $opt in
    j) JWT_FILE="$OPTARG" ;;
    i) NIM_IP="$OPTARG" ;;
    u) USERNAME="$OPTARG" ;;
    p) PASSWORD="$OPTARG" ;;
    s) USE_CASE="$OPTARG" ;;
    *) usage ;;
  esac
done

# Check if all required arguments are provided
if [ -z "${JWT_FILE:-}" ] || [ -z "${NIM_IP:-}" ] || [ -z "${USERNAME:-}" ] || [ -z "${PASSWORD:-}" ] || [ -z "${USE_CASE:-}" ]; then
  usage
fi

echo "Running $USE_CASE report"

# Ensure /tmp directory exists or else create it and proceed
if [ ! -d "/tmp" ]; then
  echo "/tmp directory does not exist. Creating it now..."
  mkdir -p /tmp || { echo "Failed to create /tmp directory. Exiting."; exit 1; }
fi

# Read JWT contents
if [ ! -f "$JWT_FILE" ]; then
  echo -e "JWT file '$JWT_FILE' not found.$" >&2
  exit 1
fi
JWT_CONTENT=$(<"$JWT_FILE")

# Encode credentials
AUTH_HEADER=$(echo -n "$USERNAME:$PASSWORD" | base64)

# Check connectivity to NGINX Instance Manager IP and the F5 licensing server (product.apis.f5.com)
echo -e "Checking connectivity to NGINX Instance Manager and F5 licensing server..."

# Function to test ping
check_ping() {
  local host=$1
  echo "Pinging $host... "
  if ! ping -c 2 -W 2 "$host" > /dev/null 2>&1; then
    echo -e "Cannot reach $host. Please check your network, DNS or check if any proxy is set.$" >&2
    exit 1
  fi
  echo -e "$host is reachable."
}

# Call the function for each host
is_ipv4() {
  local ip=$1
  if [[ $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
    IFS='.' read -r -a octets <<< "$ip"
    for octet in "${octets[@]}"; do
      if ((octet < 0 || octet > 255)); then
        return 1
      fi
    done
    return 0
  else
    return 1
  fi
}
echo "Checking connectivity to NGINX Instance Manager using Curl ..."
if ! curl -sk --output /dev/null --silent --fail --max-time $CURL_TIMEOUT "https://$NIM_IP"; then
  echo -e "The NGINX Instance Manager UI is not reachable on $NIM_IP"
  exit 1
fi 
echo "Checking connectivity to F5 licensing server..."
SERVER_RESPONSE=$(curl -v --max-time $CURL_TIMEOUT https://product.apis.f5.com 2>&1)

# Check if the server is reachable by verifying connection was established
if echo "$SERVER_RESPONSE" | grep -q "Connected to product.apis.f5.com" && echo "$SERVER_RESPONSE" | grep -q "server accepted"; then
  echo -e "The licensing server is reachable on product.apis.f5.com"
else
  echo -e "The licensing server is not reachable on product.apis.f5.com"
  echo -e "Connection details: $SERVER_RESPONSE"
  exit 1
fi 

# NGINX Instance Manager Version check 
VERSION_JSON=$(curl -sk -X GET "https://$NIM_IP/api/platform/v1/modules/versions" \
  --header "Content-Type: application/json" \
  --header "Authorization: Basic $AUTH_HEADER")
NIM_VER=$(echo "$VERSION_JSON" | sed -E 's/.*"nim"[ \t]*:[ \t]*"([0-9]+\.[0-9]+)(\.[0-9]+)?".*/\1/')
echo "Current version of NGINX Instance Manager is $NIM_VER"

# Construct JSON payload
JSON_PAYLOAD=$(cat <<EOF
  {
    "metadata": {
      "name": "license"
    },
    "desiredState": {
      "content": "$JWT_CONTENT"
    }
  }
EOF
)

# Send GET request and capture response and status code
response=$(curl -sk -w "%{http_code}" -o /tmp/device_mode.json "https://$NIM_IP/api/platform/v1/report/device_mode" -H 'accept: application/json' -H "Authorization: Basic $AUTH_HEADER")

# Extract status code and response body
http_code="${response: -3}"
body=$(cat /tmp/device_mode.json)

# Check response code
if [[ "$http_code" != "200" ]]; then
  echo "Request failed with status code $http_code"
  exit 1
fi

# Parse device_mode using jq
device_mode=$(echo "$body" | jq -r '.device_mode')

# Use the value
echo "Device mode is: $device_mode"

# Check value and act
if [[ "$device_mode" == "CONNECTED" ]]; then
  echo "Device mode is CONNECTED. This script is only for DISCONNECTED mode"
  exit 1
fi

ORIGIN="https://$NIM_IP"
REFERER="$ORIGIN/ui/settings/license"

if [[ "$USE_CASE" == "initial" ]]; then
  echo "Applying JWT license"
  sleep 5  
  RESPONSE=$(curl -sS -k --max-time 10 -w "\n%{http_code}" -X POST "https://$NIM_IP/api/platform/v1/license?telemetry=true" \
    -H "Origin: $ORIGIN" \
    -H "Referer: $REFERER" \
    -H "Content-Type: application/json" \
    -H "Authorization: Basic $AUTH_HEADER" \
    -d "$JSON_PAYLOAD")
  echo "Uploaded License"
  HTTP_BODY=$(echo "$RESPONSE" | sed '$d')
  HTTP_STATUS=$(echo "$RESPONSE" | tail -n1)
  if [ "$HTTP_STATUS" -ne 202 ]; then
    echo -e "HTTP request failed with status code $HTTP_STATUS.\nResponse: $HTTP_BODY$" >&2
    if echo "$HTTP_BODY" | jq -r '.message' | grep -q "failed to register token. already registered"; then
      echo -e "NGINX Instance Manager already registered and licensed.\nIf needed, terminate the current license manually in the NGINX Instance Manager UI and re-run the script with the correct license.\nhttps://docs.nginx.com/nginx-instance-manager/disconnected/add-license-disconnected-deployment/"
    fi
    exit 1
  fi
fi

if [[ "$NIM_VER" < "2.18" ]]; then
  echo "NGINX Instance Manager version $NIM_VER is not supported by this script. Please use NGINX Instance Manager 2.18 or later"
  exit 1
elif [[ "$NIM_VER" == "2.18" ]] || [[ "$NIM_VER" == "2.19" ]]; then
  echo "NGINX Instance Manager version $NIM_VER detected."
  ORIGIN="https://$NIM_IP"

  # Send the PUT request and separate body and status code
  PUT_RESPONSE_CODE=$(curl -k -s -w "%{http_code}" -o /tmp/put_response.json --location --request PUT "https://$NIM_IP/api/platform/v1/license?telemetry=true" \
    --header "Origin: $ORIGIN" \
    --header "Referer: https://$NIM_IP/ui/settings/license" \
    --header "Content-Type: application/json" \
    --header "Authorization: Basic $AUTH_HEADER" \
    --data '{
      "desiredState": {
          "content": "'"$JWT_CONTENT"'",
          "type": "JWT",
          "features": [
              {"limit": 0, "name": "NGINX_NAP_DOS", "valueType": ""},
              {"limit": 0, "name": "IM_INSTANCES", "valueType": ""},
              {"limit": 0, "name": "TM_INSTANCES", "valueType": ""},
              {"limit": 0, "name": "DATA_PER_HOUR_GB", "valueType": ""},
              {"limit": 0, "name": "NGINX_INSTANCES", "valueType": ""},
              {"limit": 0, "name": "NGINX_NAP", "valueType": ""},
              {"limit": 0, "name": "SUCCESSFUL_API_CALLS_MILLIONS", "valueType": ""},
              {"limit": 0, "name": "IC_PODS", "valueType": ""},
              {"limit": 0, "name": "IC_K8S_NODES", "valueType": ""}
          ]
      },
      "metadata": {
          "name": "license"
      }
    }')

  echo "Response status code: $PUT_RESPONSE_CODE"

  if [[ "$PUT_RESPONSE_CODE" == "200" ]]; then
    echo -e "(legacy): License applied successfully in DISCONNECTED mode for version $NIM_VER."
  else
    echo -e "(legacy): License PUT request failed. Status code: $PUT_RESPONSE_CODE$"
    echo "clear the license database and re-trigger the script again"
    exit 1
  fi
fi

if [[ "$USE_CASE" != "telemetry" ]]; then
  RESPONSE=$(curl -sS -k --max-time 10 -w "\n%{http_code}" -X POST "https://$NIM_IP/api/platform/v1/license?telemetry=true" \
    -H "Origin: $ORIGIN" \
    -H "Referer: $REFERER" \
    -H "Content-Type: application/json" \
    -H "Authorization: Basic $AUTH_HEADER" \
    -d "$JSON_PAYLOAD")

  HTTP_BODY=$(echo "$RESPONSE" | sed '$d')
  HTTP_STATUS=$(echo "$RESPONSE" | tail -n1)

  echo -e "License applied successfully in DISCONNECTED mode."
fi

sleep 5
echo "Executing telemetry tasks"
if [[ "$NIM_VER" == "2.18" ]] || [[ "$NIM_VER" == "2.19" ]]; then
  if [[ "$USE_CASE" == "initial" ]]; then
    HTTP_RESPONSE=$(curl -k -sS -w "\n%{http_code}" --location "https://$NIM_IP/api/platform/v1/report/download?format=zip&reportType=initial" \
      --header "accept: application/json" \
      --header "authorization: Basic $AUTH_HEADER" \
      --header "content-type: application/json" \
      --header "origin: https://$NIM_IP" \
      --output /tmp/response.zip)
  else
     prepare_usage_command="curl --insecure --location 'https://$NIM_IP/api/platform/v1/report/download?format=zip&reportType=telemetry&telemetryAction=prepare' \
          --header 'accept: application/json' \
          --header 'authorization: Basic $AUTH_HEADER' \
          --header 'referer: https://$NIM_IP/ui/settings/license'"
    report_save_path="${output_file:-/tmp/response.zip}"

    download_usage_command="curl --insecure --location 'https://$NIM_IP/api/platform/v1/report/download?format=zip&reportType=telemetry&telemetryAction=download' \
      --header 'accept: */*' \
      --header 'authorization: Basic $AUTH_HEADER' \
      --output \"$report_save_path\""
    
    if [ "$USE_CASE" == "telemetry" ]; then
      echo "Running telemetry stage: "
      response=$(eval $prepare_usage_command)
      sleep 2
      if echo "$response" | grep -q '"telemetry":"Report generation in progress"'; then
        echo -e "Success: Report generation is in progress."
      else
        echo -e "Failure: Report generation not in progress or unexpected response."
        exit 1
      fi
      echo "Running command: $download_usage_command"
      eval $download_usage_command
    else
      echo "Running command: $download_usage_command"
      eval $download_usage_command
    fi
  fi
else
  HTTP_RESPONSE=$(curl -k -sS -w "\n%{http_code}" --location "https://$NIM_IP/api/platform/v1/report/download?format=zip" \
  --header "accept: application/json" \
  --header "authorization: Basic $AUTH_HEADER" \
  --header "content-type: application/json" \
  --header "origin: https://$NIM_IP" \
  --output /tmp/response.zip)

  HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tail -n1)
  if [ "$HTTP_STATUS" -ne 200 ]; then
    echo -e "Failed to download usage report from NGINX Instance Manager. HTTP Status Code: $HTTP_STATUS" >&2
    echo "Please verify that NGINX Instance Manager is reachable and the credentials are correct." >&2
    echo "(or) Verify that NGINX Instance Manager is licensed before using the 'telemetry' flag (run it with 'initial' first)."
    rm -f /tmp/response.zip
    exit 1
  fi
fi

echo -e "Usage report downloaded successfully as '/tmp/response.zip'."

echo "Uploading the usage report to F5 Licensing server"
TEEM_UPLOAD_URL="https://product.apis.f5.com/ee/v1/entitlements/telemetry/bulk"

UPLOAD_RESULT=$(curl -sS -w "\n%{http_code}" --location "$TEEM_UPLOAD_URL" \
  --header "Authorization: Bearer $JWT_CONTENT" \
  --form "file=@/tmp/response.zip")

UPLOAD_STATUS=$(echo "$UPLOAD_RESULT" | tail -n1)
UPLOAD_BODY=$(echo "$UPLOAD_RESULT" | sed '$d')

if [ "$UPLOAD_STATUS" -ne 202 ]; then
  echo -e "Usage report upload failed. HTTP Status: $UPLOAD_STATUS$" >&2
  echo "Response Body: $UPLOAD_BODY" >&2
  exit 1
fi

if ! echo "$UPLOAD_BODY" | jq empty >/dev/null 2>&1; then
  echo -e "Upload response is not valid JSON. Response: $UPLOAD_BODY$" >&2
  exit 1
fi

STATUS_LINK=$(echo "$UPLOAD_BODY" | jq -r '.statusLink // empty')
if [ -z "$STATUS_LINK" ]; then
  echo -e "Failed to extract statusLink from the upload response. Response: $UPLOAD_BODY$" >&2
  exit 1
fi

echo "StatusLink extracted: $STATUS_LINK"
STATUS_ID=$(echo "$STATUS_LINK" | sed 's|/ee/v1/entitlements/telemetry/bulk/status/||')

echo "Validating the report status"
echo "Validating report status using status ID: $STATUS_LINK"

STATUS_URL="https://product.apis.f5.com/ee/v1/entitlements/telemetry/bulk/status/$STATUS_ID"

sleep 5
STATUS_RESPONSE=$(curl -k -sS -w "\n%{http_code}" --location "$STATUS_URL" \
  --header "Authorization: Bearer $JWT_CONTENT")

STATUS_BODY=$(echo "$STATUS_RESPONSE" | sed '$d')
STATUS_CODE=$(echo "$STATUS_RESPONSE" | tail -n1)

if [ "$STATUS_CODE" -ne 200 ]; then
  echo -e "Status check failed. HTTP Status: $STATUS_CODE$" >&2
  echo "Response Body: $STATUS_BODY" >&2
  exit 1
fi

if ! echo "$STATUS_BODY" | jq empty >/dev/null 2>&1; then
  echo -e "Invalid JSON in status body: $STATUS_BODY$" >&2
  exit 1
fi

PERCENTAGE_COMPLETE=$(echo "$STATUS_BODY" | jq -r '.percentageComplete')
PERCENTAGE_SUCCESSFUL=$(echo "$STATUS_BODY" | jq -r '.percentageSuccessful')
READY_FOR_DOWNLOAD=$(echo "$STATUS_BODY" | jq -r '.readyForDownload')

TIME_LIMIT=30
START_TIME=$(date +%s)

elapsed_time() {
  echo $(($(date +%s) - $START_TIME))
}

while true; do
  if [ "$PERCENTAGE_COMPLETE" -eq "100" ] && [ "$READY_FOR_DOWNLOAD" == "true" ]; then
    echo -e "Validating Report."
    break
  fi

  if [ $(elapsed_time) -ge "$TIME_LIMIT" ]; then
    echo -e "Time limit exceeded. Report validation failed."
    echo "  percentageComplete: $PERCENTAGE_COMPLETE"
    echo "  percentageSuccessful: $PERCENTAGE_SUCCESSFUL"
    echo "  readyForDownload: $READY_FOR_DOWNLOAD"
    echo "  F5 upload issue failed even after 30 seconds"
    echo "  re-run the script"
    exit 1
  fi

  echo -e "Report validation failed. Waiting for conditions to be met...$"
  echo "  percentageComplete: $PERCENTAGE_COMPLETE"
  echo "  percentageSuccessful: $PERCENTAGE_SUCCESSFUL"
  echo "  readyForDownload: $READY_FOR_DOWNLOAD"

  sleep 5
done

echo -e "Report validated successfully. All conditions met."

echo "Downloading report from F5 License server..."
DOWNLOAD_URL="https://product.apis.f5.com/ee/v1/entitlements/telemetry/bulk/download/$STATUS_ID"
DOWNLOAD_RESPONSE=$(curl -sS -w "%{http_code}" --location "$DOWNLOAD_URL" \
  --header "Authorization: Bearer $JWT_CONTENT" \
  --output /tmp/response_teem.zip)

HTTP_STATUS=$(echo "$DOWNLOAD_RESPONSE" | tail -n1)
if [ "$HTTP_STATUS" -ne 200 ]; then
  echo -e "Failed to download the report from F5. HTTP Status Code: $HTTP_STATUS$" >&2
  exit 1
fi

echo -e "Report downloaded successfully from F5 as '/tmp/response_teem.zip'."

echo "Uploading the license acknowledgement to NGINX Instance Manager..."
UPLOAD_URL="https://$NIM_IP/api/platform/v1/report/upload"
UPLOAD_RESPONSE=$(curl -k -sS --location "$UPLOAD_URL" \
  --header "Authorization: Basic $AUTH_HEADER" \
  --form "file=@/tmp/response_teem.zip" \
  -w "%{http_code}" -o /tmp/temp_response.json)

HTTP_STATUS=$(echo "$UPLOAD_RESPONSE" | tail -n1)
UPLOAD_MESSAGE=$(cat /tmp/temp_response.json | jq -r '.message')

if ! [[ "$HTTP_STATUS" =~ ^[0-9]+$ ]]; then
  echo -e "Invalid HTTP status code. Response: $UPLOAD_RESPONSE$" >&2
  exit 1
fi

if [ "$UPLOAD_MESSAGE" != "Report uploaded successfully." ] || [ "$HTTP_STATUS" -ne 200 ]; then
  echo -e "Upload failed. Response: $UPLOAD_RESPONSE$" >&2
  exit 1
fi
echo -e "Acknowledgement uploaded successfully to NGINX Instance Manager."

To license NGINX Instance Manager, complete each of the following steps in order.

Important: The curl command to add a license won’t work if a license has already been added.

Run these curl commands on a system that can access NGINX Instance Manager and connect to https://product.apis.f5.com/ on port 443. Replace each placeholder with your specific values.

TLS certificate validation
The -k flag skips SSL certificate validation. Use this only if your NGINX Instance Manager is using a self-signed certificate or if the certificate is not trusted by your system.
  1. Add the license to NGINX Instance Manager:

    bash
    curl -k --location 'https://<NIM-FQDN>/api/platform/v1/license?telemetry=true' \
    --header 'Origin: https://<NIM-FQDN>' \
    --header 'Referer: https://<NIM-FQDN>/ui/settings/license' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Basic <base64-encoded-credentials>' \
    --data '{
      "metadata": {
        "name": "license"
      },
      "desiredState": {
        "content": "<JSON-web-token>"
      }
    }'
  2. Poll the license status on NGINX Instance Manager:

    Use this command to check the current license status. Look for INITIALIZE_ACTIVATION_COMPLETE or CONFIG_REPORT_READY in the status field. Poll periodically if necessary.

    bash
    curl -k "https://<NIM-FQDN>/api/platform/v1/license" \
    --header "accept: application/json" \
    --header "authorization: Basic <base64-encoded-credentials>" \
    --header "referer: https://<NIM-FQDN>/ui/settings/license"
  3. Update the license configuration on NGINX Instance Manager (not required in 2.20 or later):

    This step ensures that the license configuration is fully applied.

    bash
    curl -k --location --request PUT "https://<NIM-FQDN>/api/platform/v1/license?telemetry=true" \
    --header "Origin: https://<NIM-FQDN>" \
    --header "Referer: https://<NIM-FQDN>/ui/settings/license" \
    --header "Content-Type: application/json" \
    --header "Authorization: Basic <base64-encoded-credentials>" \
    --data '{
      "desiredState": {
        "content": "",
        "type": "JWT",
        "features": [
          {"limit": 0, "name": "NGINX_NAP_DOS", "valueType": ""},
          {"limit": 0, "name": "IM_INSTANCES", "valueType": ""},
          {"limit": 0, "name": "TM_INSTANCES", "valueType": ""},
          {"limit": 0, "name": "DATA_PER_HOUR_GB", "valueType": ""},
          {"limit": 0, "name": "NGINX_INSTANCES", "valueType": ""},
          {"limit": 0, "name": "NGINX_NAP", "valueType": ""},
          {"limit": 0, "name": "SUCCESSFUL_API_CALLS_MILLIONS", "valueType": ""},
          {"limit": 0, "name": "IC_PODS", "valueType": ""},
          {"limit": 0, "name": "IC_K8S_NODES", "valueType": ""}
        ]
      },
      "metadata": {
        "name": "license"
      }
    }'
  4. Download the initial usage report:

    bash
    curl -k --location 'https://<NIM-FQDN>/api/platform/v1/report/download?format=zip&reportType=initial' \
    --header 'accept: */*' \
    --header 'Authorization: Basic <base64-encoded-credentials>' \
    --output report.zip
  5. Submit the usage report to F5 for verification:

    bash
    curl --location 'https://product.apis.f5.com/ee/v1/entitlements/telemetry/bulk' \
    --header "Authorization: Bearer $(cat /path/to/jwt-file)" \
    --form 'file=@"<path-to-report>.zip"'

    After running this command, look for the “statusLink” in the response. The report-id is the last part of the “statusLink” value (the UUID). For example:

    {"statusLink":"/status/2214e480-3401-43a3-a54c-9dc501a01f83"}

    In this example, the report-id is 2214e480-3401-43a3-a54c-9dc501a01f83.

    You’ll need to use your specific report-id in the following steps.

  6. Check the status of the usage acknowledgment:

    Replace <report-id> with your specific ID from the previous response.

    bash
    curl --location 'https://product.apis.f5.com/ee/v1/entitlements/telemetry/bulk/status/<report-id>' \
    --header "Authorization: Bearer $(cat /path/to/jwt-file)"
  7. Download the usage acknowledgement from F5:

    bash
    curl --location 'https://product.apis.f5.com/ee/v1/entitlements/telemetry/bulk/download/<report-id>' \
    --header "Authorization: Bearer $(cat /path/to/jwt-file)" \
    --output <path-to-acknowledgement>.zip
  8. Upload the usage acknowledgement to NGINX Instance Manager:

    bash
    curl -k --location 'https://<NIM-FQDN>/api/platform/v1/report/upload' \
    --header 'Authorization: Basic <base64-encoded-credentials>' \
    --form 'file=@"<path-to-acknowledgement>.zip"'

To add a license:

  1. Go to the FQDN of your NGINX Instance Manager host and log in.
  2. Select the Settings (gear) icon. The Licenses > Overview opens at https://<NIM_FQDN>/ui/settings/license.
  3. Select Get Started.
  4. Upload your license file by selecting Browse or dragging the file into the form.
  5. Select Add.

Download the initial usage report to send to F5:

  • On the License > Overview page, select Download License Report.

You need to submit the usage report to F5 and download the acknowledgment over REST. To do so, follow steps 5–7 in the REST tab in this section.

To upload the usage acknowledgement:

  1. On the License > Overview page, select Upload Usage Acknowledgement.
  2. Upload the acknowledgement by selecting Browse or dragging the file into the form.
  3. Select Add.