Applications Azure

Nightscout CGM Remote Monitor on Ubuntu 24.04 on Azure User Guide

| Product: Nightscout CGM Remote Monitor on Ubuntu 24.04 LTS on Azure

Overview

This image runs Nightscout (cgm-remote-monitor) 15.0.7, the open source, self-hosted CGM remote monitor, on Ubuntu 24.04 LTS. Nightscout stores continuous glucose monitoring data in a private database and presents it on a live web dashboard, with a REST API that uploaders (xDrip+, AndroidAPS, Loop and others) write to and that caregivers can read from. It is run from /opt/nightscout on the Node.js 22 LTS runtime by an unprivileged nightscout system account under a systemd service that starts it on boot and restarts it on failure. A local MongoDB 7.0 Community database stores every glucose entry, treatment and profile.

Nightscout listens on the loopback address 127.0.0.1:1337 by design and is never exposed directly. nginx is installed as a reverse proxy on port 80 that forwards every request to Nightscout. Visitors reach the dashboard on the standard HTTP port.

Secured from first boot. Two secrets are generated fresh and unique on the first boot of every VM and are never baked into the image: the API secret (Nightscout's write/admin passphrase) and the MongoDB password. Access is set to denied by default, so the dashboard and API return nothing until the API secret is supplied - no default login ever ships.

What is included:

  • Nightscout 15.0.7, run by systemd as the unprivileged nightscout user
  • The Nightscout dashboard and REST API on :80 (nginx reverse proxy to 127.0.0.1:1337)
  • A per-VM API secret and MongoDB password set on first boot and recorded in a root-only file
  • MongoDB 7.0 Community, bound to loopback with authentication enabled, its data directory on a dedicated Azure data disk at /var/lib/nightscout
  • mongod.service, nightscout.service and nginx.service as systemd units, enabled and active
  • An unauthenticated /healthz endpoint for Azure Load Balancer health probes
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point; size up for many concurrent followers. NSG inbound: allow 22/tcp from your management network and 80/tcp for the dashboard and API. Nightscout serves plain HTTP on port 80; for production, terminate TLS in front of it with your own domain, since glucose data is sensitive and uploaders should connect over HTTPS.

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Nightscout by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Review the dedicated data disk on the Disks tab, then Review + create then Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name nightscout \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name nightscout --port 80 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

Nightscout is served by nginx on port 80, which reverse-proxies to the Node.js app on 127.0.0.1:1337, which in turn talks to MongoDB on 127.0.0.1:27017. Confirm all three services are active and the ports are bound:

systemctl is-active mongod nightscout nginx nightscout-firstboot
sudo ss -tlnp | grep -E ':80 |:1337 |:27017 '

Expected output:

active
active
active
active
LISTEN 0      511          0.0.0.0:80         0.0.0.0:*    users:(("nginx",pid=...))
LISTEN 0      511        127.0.0.1:1337       0.0.0.0:*    users:(("node",pid=...))
LISTEN 0      4096       127.0.0.1:27017      0.0.0.0:*    users:(("mongod",pid=...))
LISTEN 0      511             [::]:80            [::]:*    users:(("nginx",pid=...))

mongod, nightscout, nginx and nightscout-firstboot active, with nginx on :80, Nightscout on 127.0.0.1:1337 and MongoDB on 127.0.0.1:27017

Step 5 - Retrieve your API secret

On the first boot of every VM, nightscout-firstboot.service generates a unique API secret and MongoDB password and writes them - together with the dashboard URL - into a root-only file. Read it with:

sudo cat /root/nightscout-credentials.txt

The API secret unlocks the dashboard and authorises writes to the REST API. Uploaders authenticate by sending the SHA1 hash of this secret as the api-secret HTTP header. Keep this file safe; anyone with the API secret can read and write your glucose data.

The per-VM Nightscout credentials file, with the generated API secret and MongoDB password

Step 6 - Confirm the stack and health endpoint

nginx serves an unauthenticated /healthz endpoint for load balancer probes. Confirm the Node.js and MongoDB versions and that the dashboard responds:

node -v
mongod --version | head -1
curl -sI http://127.0.0.1/healthz | head -1
curl -s http://127.0.0.1/ | grep -o '<title>[^<]*</title>'

Expected output:

v22.23.1
db version v7.0.37
HTTP/1.1 200 OK
<title>Nightscout</title>

Node.js 22 and MongoDB 7.0 versions, the healthz endpoint returning 200 and the Nightscout dashboard title

Step 7 - Open the dashboard and authenticate

Browse to http://<vm-public-ip>/. Because access is denied by default, the dashboard first loads locked - no data is shown until you authenticate.

The Nightscout dashboard on first load, locked until you authenticate

Click the padlock icon (or open the menu and choose Authentication Status), paste the API secret from Step 5, and confirm. Your browser stores the hashed secret locally and the dashboard unlocks, showing the glucose chart and the current reading.

The authenticated Nightscout dashboard, showing the glucose chart with a sample reading and the current value

Step 8 - Upload and read a glucose entry over the REST API

Uploaders and integrations use the Nightscout REST API v1. Authentication is the SHA1 hash of your API secret, sent as the api-secret header. The example below computes the hash, posts a sample SGV (sensor glucose value) entry, and reads it back. Run it on the VM (or from any host, replacing 127.0.0.1 with the VM's address):

SECRET=$(sudo grep '^NIGHTSCOUT_API_SECRET=' /root/nightscout-credentials.txt | cut -d= -f2-)
HASH=$(printf '%s' "$SECRET" | sha1sum | cut -d' ' -f1)
TS=$(date +%s%3N)

# An unauthenticated write is rejected (secure by default):
curl -s -o /dev/null -w 'unauthenticated POST -> HTTP %{http_code}\n' \
  -X POST http://127.0.0.1/api/v1/entries.json -H 'Content-Type: application/json' \
  --data "[{\"type\":\"sgv\",\"sgv\":120,\"date\":${TS},\"direction\":\"Flat\"}]"

# An authenticated write succeeds and echoes the stored entry:
curl -s -X POST http://127.0.0.1/api/v1/entries.json \
  -H "api-secret: ${HASH}" -H 'Content-Type: application/json' \
  --data "[{\"type\":\"sgv\",\"sgv\":120,\"date\":${TS},\"direction\":\"FortyFiveUp\",\"device\":\"guide-demo\"}]"

# Read it back:
curl -s -H "api-secret: ${HASH}" 'http://127.0.0.1/api/v1/entries.json?count=1'

Expected output:

unauthenticated POST -> HTTP 401
[{"type":"sgv","sgv":120,"date":1784599618173,"direction":"FortyFiveUp","device":"guide-demo","utcOffset":0,"sysTime":"2026-07-21T02:06:58.173Z","_id":"6a5ed4429f073ee2f61195b9"}]
[{"_id":"6a5ed4429f073ee2f61195b9","sysTime":"2026-07-21T02:06:58.173Z","type":"sgv","date":1784599618173,"device":"guide-demo","direction":"FortyFiveUp","sgv":120,"utcOffset":0,"mills":1784599618173}]

Point your CGM uploader app at http://<vm-public-ip> with the same API secret and your live readings will begin to flow onto the dashboard.

Step 9 - Review glucose history with Reports

The Reports page renders longer-term views of your data - daily glucose profiles, distribution, day-to-day charts and more - across a date range you choose. Open it from the menu, or browse to http://<vm-public-ip>/report/.

The Nightscout Reports page for reviewing glucose history over a date range

Step 10 - Configure your treatment profile

The Profile Editor is where you set the parameters Nightscout uses to interpret your data - insulin duration (DIA), insulin-to-carb ratios, insulin sensitivity factor, basal rates and your target glucose range. Open it from the menu, or browse to http://<vm-public-ip>/profile/. Adjust the values for your care plan and save.

The Nightscout Profile Editor for setting DIA, insulin-to-carb ratio, sensitivity and target range

Step 11 - Confirm data lives on the dedicated disk

All MongoDB data - every glucose entry, treatment and profile - lives under /var/lib/nightscout, which is a dedicated Azure data disk captured into the image and re-provisioned on every VM:

df -h /var/lib/nightscout | tail -1
findmnt -no SOURCE,TARGET,FSTYPE /var/lib/nightscout
sudo ls /var/lib/nightscout/mongodb | head -5

Expected output:

/dev/sdc         20G  301M   19G   2% /var/lib/nightscout
/dev/sdc /var/lib/nightscout ext4
WiredTiger
WiredTiger.lock
WiredTiger.turtle
WiredTiger.wt
WiredTigerHS.wt

The MongoDB dbPath on the dedicated ext4 data disk, listing the WiredTiger data files

Maintenance

  • Back up your data: everything Nightscout stores lives in MongoDB's data files under /var/lib/nightscout. Snapshot the data disk, or use mongodump/mongorestore for logical backups.
  • Rotate the API secret: the API secret lives in the Nightscout process environment at /etc/nightscout/nightscout.env (readable by root only). Edit API_SECRET, then sudo systemctl restart nightscout. Re-enter the new secret in each browser and uploader.
  • Add followers and roles: Nightscout supports named access tokens with fine-grained roles from the Admin Tools page, so followers do not need the full API secret. See the upstream documentation.
  • Security updates: unattended security upgrades are enabled, so the OS keeps itself patched. Reboot when a new kernel is installed.
  • TLS: for production, front Nightscout with your own domain and a TLS-terminating reverse proxy or Azure Application Gateway - glucose data is sensitive and should travel over HTTPS.

Support

cloudimg provides 24/7/365 expert technical support for this image. Contact support@cloudimg.co.uk. Nightscout (cgm-remote-monitor) is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). This image is provided by cloudimg; additional charges apply for build, maintenance and 24/7 support.