Deployment guide

Nightscout

Overview

Nightscout (cgm-remote-monitor) is an open-source, self-hosted continuous glucose monitoring (CGM) remote monitor. It stores CGM data in a private database and presents it on a live web dashboard. A REST API lets uploaders (xDrip+, AndroidAPS, Loop and others) write data and lets caregivers read it.

This image runs Nightscout (cgm-remote-monitor) 15.0.7 on Ubuntu 24.04 LTS, managed by systemd as the unprivileged nightscout user. It is secured from first boot: two secrets are generated fresh on every VM, and no default login ever ships.

What you get:

  • Nightscout 15.0.7 run from /opt/nightscout on the Node.js 22 LTS runtime, by the unprivileged nightscout system account under a systemd service that starts on boot and restarts on failure
  • A local MongoDB 7.0 Community database that stores every glucose entry, treatment and profile. It is bound to loopback with authentication enabled, and its data directory is on a dedicated Azure data disk at /var/lib/nightscout.
  • Nightscout listening on the loopback address 127.0.0.1:1337 by design. It is never exposed directly.
  • The Nightscout dashboard and REST API on :80, through an nginx reverse proxy to 127.0.0.1:1337. Visitors reach the dashboard on the standard HTTP port.
  • A per-VM API secret (Nightscout's write/admin passphrase) and MongoDB password, generated fresh on the first boot of every VM, never baked into the image, and recorded in a root-only file
  • Access set to denied by default, so the dashboard and API return nothing until the API secret is supplied
  • 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 SecureAnyCloud 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, because 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 SecureAnyCloud, 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 select Review + create, followed by Create.

Step 2 - Deploy from the Azure CLI

Deploy the image from the Azure CLI. Replace the values in angle brackets with your own:

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:nightscout-ubuntu-24-04:default:latest
az vm create \
  --resource-group <your-rg> \
  --name nightscout \
  --image sac1647283583153:nightscout-ubuntu-24-04:default:latest \
  --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

Connect to the VM over SSH:

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

nginx serves Nightscout on port 80 and reverse-proxies to the Node.js app on 127.0.0.1:1337. The app in turn talks to MongoDB on 127.0.0.1:27017. Confirm that 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=...))

Step 5 - Retrieve your API secret

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

sudo cat /root/nightscout-credentials.txt

The API secret unlocks the dashboard and authorizes 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.

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 confirm 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>

Step 7 - Open the dashboard and authenticate

Browse to http://<vm-public-ip>/. Access is denied by default, so the dashboard first loads locked. No data is shown 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. It shows the glucose chart and the current reading.

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 after you replace 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. Your live readings then begin to flow onto the dashboard.

Step 9 - Review glucose history with Reports

The Reports page renders longer-term views of your data across a date range you choose. The views include daily glucose profiles, distribution and day-to-day charts.

Open the page from the menu, or browse to http://<vm-public-ip>/report/.

Step 10 - Configure your treatment profile

Use the Profile Editor to set the parameters that Nightscout uses to interpret your data. These are insulin duration (DIA), insulin-to-carb ratios, insulin sensitivity factor, basal rates and your target glucose range.

Open the editor from the menu, or browse to http://<vm-public-ip>/profile/. Adjust the values for your care plan and save.

Step 11 - Confirm data lives on the dedicated disk

All MongoDB data lives under /var/lib/nightscout. This covers every glucose entry, treatment and profile. The path 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

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 run 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

SecureAnyCloud provides 24/7/365 expert technical support for this image. Contact sales@secureanycloud.com.

Nightscout (cgm-remote-monitor) is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). SecureAnyCloud provides this image. Additional charges apply for build, maintenance and 24/7 support.

Deploy on Azure

Launch Nightscout CGM Remote Monitor 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