I4
Applications Azure

istSOS 4 on Ubuntu 24.04 on Azure User Guide

| Product: istSOS 4 on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and configuration of istSOS 4 on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. istSOS is an open source server for collecting, managing and publishing environmental and monitoring sensor data over open OGC standards. It implements the SensorThings API and the Sensor Observation Service data model, so you register sensors, things, observed properties and datastreams, then load and serve the time series observations they produce through a clean REST API and an interactive API explorer.

The image ships istSOS 4 (istsos4 v1.0.0) as a FastAPI application served by uvicorn behind nginx, backed by PostgreSQL 16 with the PostGIS spatial extension and a local Redis 7 instance used for token handling. The SensorThings API is served under the versioned path /istsos4/v1.1, with an interactive Swagger explorer at /istsos4/v1.1/docs. On every fresh customer virtual machine, istsos-firstboot.service rotates the istSOS administrator password, the PostgreSQL account passwords and the JWT signing key to per-VM strong values before the API is reachable, and the upstream default administrator login is proven dead. A demo network of five sensor stations, two observed properties and 1680 time series observations is seeded at build time, so the API and its explorer show real data the moment you launch.

What is included:

  • istSOS 4 (istsos4 v1.0.0) served by uvicorn from a Python 3.12 virtual environment at /opt/istsos/venv

  • istsos-api.service (uvicorn, 2 workers) fronted by nginx on TCP 80

  • istsos-firstboot.service systemd oneshot that rotates the admin password, the PostgreSQL passwords and the JWT signing key on first boot

  • PostgreSQL 16 with the PostGIS 3.4 spatial extension as the SensorThings datastore (database istsos)

  • Redis 7 from the Ubuntu 24.04 main repo for token handling

  • The SensorThings API served at /istsos4/v1.1 with an interactive Swagger explorer at /istsos4/v1.1/docs

  • Anonymous read access to the sensor collections for easy browsing, with every write requiring the administrator token

  • A seeded demo network: five sensor stations, two observed properties (rainfall and temperature), ten datastreams and 1680 observations

  • Ubuntu 24.04 LTS base with latest security patches applied at build time

  • Azure Linux Agent for seamless cloud integration and SSH key injection

  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • An active Azure subscription

  • A subscription to the istSOS 4 on Ubuntu 24.04 listing on Azure Marketplace

  • An SSH public key for VM authentication

  • A virtual network and subnet in the target region

Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is sufficient for evaluation and small monitoring networks. Scale up to Standard_D2s_v5 or larger for production networks ingesting high frequency observations from many stations.

Step 1: Deploy from the Azure Portal

Navigate to Marketplace in the Azure Portal, search for istSOS 4, select the cloudimg publisher entry, and click Create.

On the Networking tab attach a network security group that allows inbound TCP 22 from your management IP range and TCP 80 from your trusted client networks. Do not expose port 80 to the public internet without TLS — the SensorThings API ships on plain HTTP by design; terminate TLS at a reverse proxy (see Step 12).

Click Review + create, wait for validation, then Create. Deployment takes around two minutes.

Step 2: Deploy from the Azure CLI

RG="istsos-prod"
LOCATION="eastus"
VM_NAME="istsos-01"
ADMIN_USER="azureuser"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/istsos-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"

az group create --name "$RG" --location "$LOCATION"

az network vnet create \
  --resource-group "$RG" \
  --name istsos-vnet --address-prefix 10.96.0.0/16 \
  --subnet-name istsos-subnet --subnet-prefix 10.96.1.0/24

az network nsg create --resource-group "$RG" --name istsos-nsg

az network nsg rule create \
  --resource-group "$RG" --nsg-name istsos-nsg \
  --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" \
  --destination-port-ranges 22 --access Allow --protocol Tcp

az network nsg rule create \
  --resource-group "$RG" --nsg-name istsos-nsg \
  --name allow-http --priority 110 \
  --source-address-prefixes "<your-mgmt-cidr>" \
  --destination-port-ranges 80 --access Allow --protocol Tcp

az vm create \
  --resource-group "$RG" --name "$VM_NAME" \
  --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username "$ADMIN_USER" --ssh-key-values "$SSH_KEY" \
  --vnet-name istsos-vnet --subnet istsos-subnet --nsg istsos-nsg \
  --public-ip-sku Standard

Step 3: Connect via SSH

ssh azureuser@<vm-ip>

istsos-api.service and nginx will already be running and istsos-firstboot.service will already have rotated the administrator password to a per-VM value.

Step 4: Verify the istSOS Services

for s in istsos-api postgresql redis-server nginx; do printf '%-16s %s\n' "$s" "$(systemctl is-active $s)"; done

Expected output (one line per service, all active):

istsos-api       active
postgresql       active
redis-server     active
nginx            active

Confirm the listeners (nginx on 80, uvicorn on 8018, PostgreSQL and Redis on loopback):

sudo ss -tln | grep -E ':80 |:8018 |:5432 |:6379 '

istSOS 4 services active and listeners bound on a freshly launched VM

Step 5: Retrieve the Administrator Credentials

The per-VM administrator password, PostgreSQL passwords and JWT signing key are written to a root-only file at first boot:

sudo cat /stage/scripts/istsos-credentials.log

You will see (values redacted in the example below — your VM has unique per-VM values):

admin_username=admin
admin_password=<ADMIN_PASSWORD>
db_superuser_password=<DB_SUPERUSER_PASSWORD>
secret_key=<SECRET_KEY>
ISTSOS_URL=http://<vm-ip>/istsos4/v1.1

The same file is written to /root/istsos-credentials.txt. Both are mode 0600 (root only). Store the administrator password in your secret store.

Step 6: The SensorThings API Service Root

The SensorThings API is served under /istsos4/v1.1. The service root lists every entity collection:

curl -s http://localhost/istsos4/v1.1 | python3 -m json.tool | head -22

You will see the eight SensorThings collections (Things, Sensors, Datastreams, Observations, ObservedProperties, Locations, HistoricalLocations, FeaturesOfInterest), each with its URL:

The SensorThings API service root listing every entity collection

Step 7: The Interactive API Explorer

Open http://<vm-ip>/istsos4/v1.1/docs in your browser to reach the Swagger explorer. Every SensorThings operation is documented and can be tried from the browser. Read operations (the GET endpoints) are open for anonymous browsing; write operations (POST, PATCH, DELETE, shown with a padlock) require the administrator token, which you obtain through the Authorize button:

The istSOS 4 interactive Swagger API explorer with anonymous reads and padlocked writes

Step 8: Browse the Seeded Sensor Stations

A fresh VM already holds a demo network so you can explore istSOS immediately. List the seeded sensor stations (Things):

curl -s "http://localhost/istsos4/v1.1/Things?\$count=true" | python3 -m json.tool | head -20

The response lists the five seeded stations. You can confirm the full seeded dataset directly in the database:

sudo -u postgres psql -d istsos -P pager=off -c "SELECT 'Things' AS entity, count(*) FROM sensorthings.\"Thing\" UNION ALL SELECT 'Datastreams', count(*) FROM sensorthings.\"Datastream\" UNION ALL SELECT 'Observations', count(*) FROM sensorthings.\"Observation\" ORDER BY 1;"

The live GET /Things response listing the five seeded sensor stations

Seeded demo network: five sensor stations, ten datastreams and 1680 observations

Step 9: View the Time Series Observations

Observations are the individual measurements recorded by each datastream. Fetch the most recent observations, newest first:

curl -s "http://localhost/istsos4/v1.1/Observations?\$top=5&\$orderby=phenomenonTime%20desc&\$count=true" | python3 -m json.tool | head -30

Each record carries a phenomenonTime and a numeric result. The seeded network holds 1680 observations spanning seven days of hourly readings for rainfall and temperature:

The live GET /Observations response showing real time series measurements

Step 10: Authenticate and Write

Reads are anonymous; writes require an administrator JSON Web Token. Log in with the per-VM administrator credentials to obtain a token, then use it to create a new Thing. The command below reads the administrator password from the credentials file, logs in, and creates an example station (writes also require a commit-message header):

BASE="http://localhost/istsos4/v1.1"
ADMIN_PW="$(sudo sed -n 's/^admin_password=//p' /stage/scripts/istsos-credentials.log | head -n1)"
TOKEN="$(curl -s -X POST "$BASE/Login" --data-urlencode 'username=admin' --data-urlencode "password=$ADMIN_PW" | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')"
curl -s -o /dev/null -w 'create example-station -> HTTP %{http_code}\n' -X POST "$BASE/Things" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -H 'commit-message: example station from the cloudimg guide' \
  -d '{"name":"example-station","description":"Created from the cloudimg guide"}'

You should see create example-station -> HTTP 201. A write attempted without the token is rejected with HTTP 401, and the upstream default admin / admin login no longer works — both are proven on every VM.

Step 11: Add Your Own Sensor Network

The SensorThings model links entities together: a Thing (a physical station) has Locations and Datastreams; each Datastream links a Sensor to an ObservedProperty and holds Observations. Using the token from Step 10, you can build a full station with a single deep-insert POST to /Things, embedding its Locations and Datastreams, then push observations to the created datastream. The interactive explorer at /istsos4/v1.1/docs documents the exact request bodies for each entity, and the OGC SensorThings API specification describes the full data model. For bulk historical loads, POST a SensorThings dataArray to /CreateObservations.

Step 12: Put TLS in Front (Production)

istSOS ships behind nginx on plain HTTP by design. For production, terminate TLS. Two common paths:

Path A — enable TLS on the on-box nginx: obtain a certificate for your DNS name and add a listen 443 ssl; server block that proxies to http://127.0.0.1:8018;. The nginx site file lives at /etc/nginx/sites-available/istsos.

Path B — Azure Application Gateway in front: create an Application Gateway with TLS termination and route the backend pool at the VM private IP on port 80. Restrict the NSG to allow inbound 80 from the App Gateway subnet only.

The cloudimg nginx-ssl-certbot-ubuntu-24-04 image is purpose-built for Path A — deploy it on a separate small VM and point it at this istSOS VM's private IP.

Step 13: Server Components

Component Path
Application code /opt/istsos/app/
Python venv /opt/istsos/venv/
Demo data generator /opt/istsos/dummy_data/generator.py
Environment file /etc/istsos/istsos.env
API systemd unit /etc/systemd/system/istsos-api.service
Firstboot script /usr/local/sbin/istsos-firstboot.sh
Firstboot service /etc/systemd/system/istsos-firstboot.service
nginx site /etc/nginx/sites-available/istsos
Credentials file /stage/scripts/istsos-credentials.log and /root/istsos-credentials.txt
Firstboot sentinel /var/lib/cloudimg/istsos-firstboot.done
PostgreSQL data /var/lib/postgresql/16/main/
PostgreSQL istSOS settings /etc/postgresql/16/main/conf.d/istsos.conf

Step 14: Managing the Services

Status:

sudo systemctl status istsos-api.service --no-pager | head -n 15

Stop / Start / Restart:

sudo systemctl restart istsos-api.service

View application logs:

sudo tail -n 50 /var/log/istsos/uvicorn.log

View firstboot log:

sudo tail -n 30 /var/log/istsos/firstboot.log 2>/dev/null || echo "firstboot log is written on first boot"

Step 15: Backup and Restore

The SensorThings datastore lives in PostgreSQL 16 on the same VM, in the istsos database. Back it up with pg_dump:

sudo -u postgres pg_dump -Fc istsos > /var/backups/istsos.dump

Restore on a new VM with pg_restore after stopping the API service. Substitute <backup-dir> for the directory holding your dump file:

sudo systemctl stop istsos-api.service
sudo -u postgres pg_restore -d istsos --clean --if-exists <backup-dir>/istsos.dump
sudo systemctl start istsos-api.service

For production, schedule a nightly pg_dump to Azure Blob Storage with azcopy.

Step 16: Troubleshooting

Cannot reach the API on port 80

  • Confirm services running: sudo systemctl is-active istsos-api.service nginx

  • Confirm listeners bound: sudo ss -tln | grep -E ':80 |:8018 '

  • Check log: sudo tail -n 50 /var/log/istsos/uvicorn.log

  • Confirm the NSG allows TCP 80 from your client source IP

Login returns 401

  • Confirm you are using the per-VM password from /stage/scripts/istsos-credentials.log, not the upstream default

  • Confirm Redis is running: sudo systemctl is-active redis-server

A write returns 422

  • Writes require both the Authorization: Bearer header and a commit-message header — include both (see Step 10)

Service fails to start

  • Check journal: sudo journalctl -u istsos-api.service --no-pager -n 100

  • Verify the datastore is reachable: sudo -u postgres psql -d istsos -c '\dt sensorthings.*' | head

Step 17: Security Recommendations

  • Rotate the administrator password again after first login and store it in your secret store

  • Restrict port 22 to your management IP ranges only

  • Restrict port 80 to trusted client networks only; pair with TLS via Step 12 for any non-trivial deployment

  • Keep read access in mind — the SensorThings collections are readable anonymously by design for easy integration; front the VM with a firewall or gateway if your observation data is sensitive

  • Schedule nightly backups of the PostgreSQL datastore (Step 15) to Azure Blob Storage

  • Shred the credentials file once the password is stored in your secret store: sudo shred -u /stage/scripts/istsos-credentials.log /root/istsos-credentials.txt

Step 18: Support and Licensing

istSOS is licensed under the Apache License 2.0 and is developed by SUPSI. There is no per-user, per-sensor, or per-server fee.

cloudimg provides commercial support for this image separately from the upstream project.

  • Email: support@cloudimg.co.uk

  • Website: www.cloudimg.co.uk

  • Support hours: 24/7 with guaranteed 24 hour response SLA

Deploy on Azure

Launch istSOS 4 on Ubuntu 24.04 with 24/7 support from cloudimg.

View on Marketplace

Need Help?

Our support team is available 24/7.

support@cloudimg.co.uk