Deployment guide

istSOS 4

Overview

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. You register sensors, things, observed properties and datastreams, then load and serve the time series observations they produce through a REST API and an interactive API explorer.

This SecureAnyCloud image runs istSOS 4 (istsos4 v1.0.0) as a FastAPI application served by uvicorn behind nginx on Ubuntu 24.04 on Azure. It is backed by PostgreSQL 16 with the PostGIS spatial extension and a local Redis 7 instance 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 virtual machine, istsos-firstboot.service rotates the istSOS administrator password, the PostgreSQL account passwords and the JWT signing key to strong per-VM values before the API is reachable. The upstream default administrator login no longer works. 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 as soon as you launch.

What you get:

  • 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, a 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 repository, used for token handling
  • The SensorThings API 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 the latest security patches applied at build time
  • Azure Linux Agent for cloud integration and SSH key injection
  • 24/7 SecureAnyCloud support with a guaranteed 24 hour response SLA

Prerequisites

Before you start, make sure you have:

  • 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. For production networks that ingest high-frequency observations from many stations, scale up to Standard_D2s_v5 or larger.

1

Deploy from the Azure Portal

In the Azure Portal, open Marketplace, search for istSOS 4, select the SecureAnyCloud 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 serves plain HTTP by design, so terminate TLS at a reverse proxy (see Step 12).

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

2

Deploy from the Azure CLI

RG="istsos-prod" LOCATION="eastus" VM_NAME="istsos-01" ADMIN_USER="azureuser" IMAGE_URN="sac1647283583153:istsos-ubuntu-24-04:default:latest" 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
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:istsos-ubuntu-24-04:default:latest
az vm create \
  --resource-group "$RG" --name "$VM_NAME" \
  --image "$IMAGE_URN" \
  --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
3

Connect via SSH

ssh azureuser@<vm-ip>

By the time you connect, istsos-api.service and nginx are running, and istsos-firstboot.service has already rotated the administrator password to a per-VM value.

4

Verify the istSOS services

Check that each service is active:

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

The output shows one line per service, and every service reports active:

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

Confirm the listeners. nginx listens on port 80, uvicorn on 8018, and PostgreSQL and Redis on loopback:

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

Retrieve the administrator credentials

On first boot, the VM writes its per-VM administrator password, PostgreSQL passwords and JWT signing key to a root-only file. Read it with sudo:

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

The file contains entries like the following. The values are redacted here, and your VM has its own unique 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 content is also written to /root/istsos-credentials.txt. Both files are mode 0600 (root only). Store the administrator password in your secret store.

6

The SensorThings API service root

The SensorThings API is served under /istsos4/v1.1. Request the service root to list every entity collection:

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

The response lists the eight SensorThings collections, each with its URL: Things, Sensors, Datastreams, Observations, ObservedProperties, Locations, HistoricalLocations and FeaturesOfInterest.

7

The interactive API explorer

Open http://<vm-ip>/istsos4/v1.1/docs in your browser to reach the Swagger explorer. It documents every SensorThings operation and lets you try each one from the browser.

Read operations (the GET endpoints) are open for anonymous browsing. Write operations (POST, PATCH and DELETE, shown with a padlock) require the administrator token, which you obtain through the Authorize button.

8

Browse the seeded sensor stations

A fresh VM already holds a demo network, so you can explore istSOS right away. 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. To confirm the full seeded dataset, query the database directly:

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;"
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, which span seven days of hourly readings for rainfall and temperature.

10

Authenticate and write

Reads are anonymous, while 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 following command 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 sac guide' \
  -d '{"name":"example-station","description":"Created from the sac guide"}'

A successful write prints 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 behaviors are verified on every VM.

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

12

Put TLS in front (production)

istSOS serves plain HTTP behind nginx by design. For production, terminate TLS using one of two common approaches.

Option 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 is at /etc/nginx/sites-available/istsos.

Option B: place Azure Application Gateway in front. Create an Application Gateway with TLS termination and point the backend pool at the VM private IP on port 80. Restrict the NSG to allow inbound port 80 from the Application Gateway subnet only.

The SecureAnyCloud nginx-ssl-certbot-ubuntu-24-04 image is built for Option A. Deploy it on a separate small VM and point it at the private IP of this istSOS VM.

13

Server components

These are the key paths on the VM:

  • Application code: /opt/istsos/app/
  • Python virtual environment: /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
  • First-boot script: /usr/local/sbin/istsos-firstboot.sh
  • First-boot service: /etc/systemd/system/istsos-firstboot.service
  • nginx site: /etc/nginx/sites-available/istsos
  • Credentials files: /stage/scripts/istsos-credentials.log and /root/istsos-credentials.txt
  • First-boot sentinel: /var/lib/sac/data/istsos-firstboot.done
  • PostgreSQL data: /var/lib/postgresql/16/main/
  • PostgreSQL istSOS settings: /etc/postgresql/16/main/conf.d/istsos.conf
14

Managing the services

Check the service status:

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

Restart the service (use stop or start in place of restart as needed):

sudo systemctl restart istsos-api.service

View the application log:

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

View the first-boot log:

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

Backup and restore

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

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

To restore on a new VM, stop the API service and run pg_restore. Replace <backup-dir> with the directory that holds 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 and copy it to Azure Blob Storage with azcopy.

16

Troubleshooting

Cannot reach the API on port 80

  • Confirm the services are running: sudo systemctl is-active istsos-api.service nginx
  • Confirm the listeners are bound: sudo ss -tln | grep -E ':80 |:8018 '
  • Check the 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 the 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
17

Security Recommendations

  • Rotate the administrator password again after your 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, and pair it with TLS (Step 12) for any non-trivial deployment.
  • Remember that read access is anonymous. 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.
  • Delete the credentials files once the password is in your secret store: sudo shred -u /stage/scripts/istsos-credentials.log /root/istsos-credentials.txt
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.

SecureAnyCloud provides commercial support for this image, separate from the upstream project.

Email: sales@secureanycloud.com

Website: secureanycloud.com

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

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure

Launch istSOS 4 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure