Skip to content

nightscout/nocturne

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2,377 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Nocturne

A modern, high-performance diabetes management platform built with .NET 10. Nocturne is a complete rewrite of the Nightscout API with full feature parity, providing native C# implementations of all endpoints with optimized performance and modern cloud-native architecture.

What is Nocturne?

Nocturne is a comprehensive diabetes data platform that provides:

  • Complete Nightscout API Implementation - All Nightscout endpoints natively implemented in C# with full compatibility
  • Data Connectors - Native integration with major diabetes platforms (Dexcom, Glooko, LibreLinkUp, MiniMed CareLink, MyFitnessPal, Nightscout)
  • Real-time Updates - WebSocket/SignalR support for live glucose readings and alerts
  • Advanced Analytics - Comprehensive glucose statistics, time-in-range calculations, and reports
  • Cloud-Native - Built on Aspire for seamless local development and cloud deployment

Architecture

Nocturne/
├── src/
│   ├── API/                        # REST API (Nightscout-compatible)
│   ├── Aspire/                     # Aspire orchestration
│   ├── Connectors/                 # Data source integrations (Dexcom, Libre, etc.)
│   ├── Core/                       # Domain models, interfaces, and constants
│   ├── Desktop/                    # Desktop application
│   ├── Infrastructure/             # EF Core data access, caching, security
│   ├── Portal/                     # Marketing website
│   ├── Services/                   # Background services
│   ├── Tools/                      # CLI tools and MCP server
│   ├── Web/                        # pnpm monorepo (SvelteKit frontend, bot, bridge)
│   └── Widgets/                    # Embeddable widgets
└── tests/                          # Comprehensive test suite

Key Features

  • Full Nightscout API Parity - All v1, v2, and v3 endpoints
  • High Performance - Optimized queries with PostgreSQL
  • Authentication - JWT-based auth with API_SECRET support
  • Real-time - SignalR hubs for live data streaming
  • Data Connectors - Dexcom Share, Glooko, LibreLinkUp, MiniMed CareLink, MyFitnessPal, Nightscout, and MyLife
  • PostgreSQL - Modern relational database with EF Core migrations
  • Observability - OpenTelemetry (OTLP) export for metrics, traces, and logs
  • Containerized - Docker support for all services

Quick Start with Aspire (Development)

Prerequisites

Aspire orchestrates all services with a single command:

aspire start

Aspire will automatically:

  • Start PostgreSQL in a container
  • Run database migrations
  • Start the Nocturne API and SvelteKit frontend
  • Launch any configured data connectors
  • Set up service discovery, health checks, and a YARP gateway

Once running, open the Aspire dashboard link from the console output to see all services. Access the app at https://localhost:1612.

Multitenancy (Custom Local Domain)

By default, Aspire serves the app at https://localhost:1612. This works for single-tenant development but WebAuthn passkeys fail on tenant subdomains because browsers reject localhost as a passkey Relying Party ID for subdomain origins.

To test multitenancy with passkeys locally:

1. Install mkcert

# Windows
winget install FiloSottile.mkcert

# macOS
brew install mkcert

# Linux — use your distro's package manager

2. Set the custom domain

cd src/Aspire/Nocturne.Aspire.Host
dotnet user-secrets set "LocalDev:Domain" "nocturne.test"

3. Add hosts file entries

Add lines to your hosts file (C:\Windows\System32\drivers\etc\hosts on Windows, /etc/hosts on macOS/Linux):

127.0.0.1  nocturne.test
127.0.0.1  demo.nocturne.test
127.0.0.1  riley.nocturne.test

Add one line per tenant slug you want to use. Hosts files don't support wildcards.

4. Start Aspire

aspire start

Aspire will automatically generate a wildcard TLS certificate for *.nocturne.test, install the mkcert CA into your system trust store, and configure the YARP gateway to use it. Access the app at https://nocturne.test.

Production Deployment (Docker Compose)

The easiest way to deploy Nocturne is with the production Docker Compose bundle. Each GitHub Release includes ready-to-use artifacts, or you can generate them locally.

Using a release

Download docker-compose.yaml and .env.example from the latest release.

# 1. Copy the env template and fill in your passwords and domain
cp .env.example .env

# 2. Start Nocturne
docker compose up -d

The production compose includes Watchtower for automatic container updates (checks daily), and omits the Aspire dashboard and Scalar API explorer. Watchtower will automatically pull new images as they are published — no manual updates needed.

First-run setup

A fresh install has no tenants, so the API answers every request with 503 {"error":"setup_required"} until the first owner secures the instance. This is expected — it's the signal for the web UI to show the setup wizard.

In a browser (normal path). Open your Nocturne site (the apex https://<BASE_DOMAIN>/). The setup wizard walks you through creating the first tenant and registering a passkey (or linking an OIDC provider). When it completes you're shown a set of recovery codes — save them. That's the whole setup.

Headless / automated setup (no browser). Trusted automation can stand up a tenant — create it, configure connectors, change settings, push data — before any human registers a passkey, using the INSTANCE_KEY from your .env. The instance key is the highest-trust service credential (cross-tenant platform admin), so treat it like a root password. Requests authenticate with two headers: X-Instance-Key carrying the SHA-256 hex of INSTANCE_KEY, and an X-Instance-Service marker naming the caller.

# The X-Instance-Key header is the SHA-256 hex of your raw INSTANCE_KEY, not the key itself.
KEY_HASH=$(printf %s "$INSTANCE_KEY" | sha256sum | cut -d' ' -f1)

# 1. Create the first tenant. This endpoint is anonymous and tenantless — call it on the apex.
curl -fsS -X POST "https://$BASE_DOMAIN/api/v4/setup/tenant" \
  -H 'Content-Type: application/json' \
  -d '{"slug":"alice","displayName":"Alice"}'

# 2. Configure the tenant as trusted automation. Target the tenant's subdomain and
#    present the instance key + service marker. Normal tenant traffic still gets 503
#    until a human completes setup, but instance-key calls are allowed through.
curl -fsS -X PUT "https://alice.$BASE_DOMAIN/api/v4/connectors/config/Dexcom/secrets" \
  -H "X-Instance-Key: $KEY_HASH" \
  -H 'X-Instance-Service: nocturne-setup-agent' \
  -H 'Content-Type: application/json' \
  -d '{ "username": "...", "password": "..." }'

When the human is ready, they open the site and register the first passkey through the normal wizard — recovery codes and all — exactly as on a brand-new instance. Their pre-configured connectors and data are already there. (A bare X-Instance-Key without the X-Instance-Service marker is ignored, so an instance key accidentally forwarded onto a browser request can't bypass setup.)

Troubleshooting

Redirected to /setup even though a tenant is already configured. Two usual causes:

  • BASE_DOMAIN is unset. The API resolves tenants as {slug}.{BASE_DOMAIN}, and the WebSocket bridge requires it. If it's empty, host→tenant resolution fails and the dashboard bounces to /setup (and the bridge logs BASE_DOMAIN is required). Set it in .env to the domain you serve Nocturne on, for both the API and web containers, then recreate them.
  • Single-tenant install served at the base domain. If your one tenant lives at the apex (https://<BASE_DOMAIN>/, no subdomain), update to the latest image — older builds reported setup_required for /api/v4/status on the apex and bounced configured single-tenant installs to /setup.

Generating locally

If you have the .NET 10 SDK and Aspire CLI installed, you can generate the production bundle from source:

dotnet run scripts/publish-release.cs              # outputs to ./release-output
dotnet run scripts/publish-release.cs ./deploy     # or specify a directory

PostgreSQL Roles

Nocturne uses three separate PostgreSQL roles for defense in depth. All three have NOBYPASSRLS so they obey Row Level Security policies, even when the database has no superuser connected.

Role Purpose Privileges
nocturne_migrator Runs EF Core migrations (schema DDL). Owns the database and public schema. CREATE, ALTER, DROP on tables. Cannot bypass RLS.
nocturne_app Runtime connection pool for the .NET API. Owns nothing. SELECT, INSERT, UPDATE, DELETE on migrator-created tables. Cannot bypass RLS.
nocturne_web SvelteKit bot framework (chat state storage). Owns only its own chat_state_* tables. CREATE on public schema (for its own tables only). No access to Nocturne tenant tables. Cannot bypass RLS.

The bootstrap user (POSTGRES_USER) is only used for initial container setup. After container-init/00-init.sh runs, all application traffic flows through the three roles above. Passwords are set via environment variables in .env.

For bring-your-own PostgreSQL (not using the bundled container), run docs/postgres/bootstrap-roles.sql once as a superuser. See the comments in that file for details.

Development

Running Tests

# Run all tests
dotnet test

# Run unit tests only
dotnet test --filter "Category!=Integration&Category!=Performance"

# Run with coverage
dotnet test --collect:"XPlat Code Coverage"

Database Migrations

# Create a new migration
cd src/Infrastructure/Nocturne.Infrastructure.Data
dotnet ef migrations add YourMigrationName

# Apply migrations
dotnet ef database update

API Documentation

API documentation is available via Scalar at https://localhost:1612/scalar when running locally.

Nocturne aims to match Nightscout's API 1:1, so any Nightscout API endpoint should be usable. Nocturne-only endpoints are scoped to v4.

Observability

Both the API and web containers are instrumented with OpenTelemetry and export metrics, traces, and logs over OTLP push when OTEL_EXPORTER_OTLP_ENDPOINT is set. With no endpoint configured, telemetry is collected in-process and discarded with negligible overhead, so there is nothing to turn off on a default install. There is no Prometheus /metrics scrape endpoint — to use Prometheus/Grafana, run an OpenTelemetry Collector with an otlp receiver and a prometheus exporter.

  • Docker Compose: add the OTEL_* variables to the nocturne-api and nocturne-web services.
  • Kubernetes (Helm): set observability.otlp.enabled: true and observability.otlp.endpoint (lights up both containers). See the Helm chart README.

Full setup guide: Observability docs.

Other stuff

License

Nocturne is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). Commercial licensing is available for organizations that need to use Nocturne without AGPL obligations — contact the maintainers for details.

Disclaimer

Nocturne is a community project and is not affiliated with or endorsed by the Nightscout Project, Abbott, Dexcom, Medtronic, Glooko, or MyFitnessPal.

Important: This software is provided as-is for personal use. Always verify glucose readings with approved medical devices. Never make treatment decisions based solely on data from this application.

Support us

Nocturne is a labor of love built by volunteers. If you find it useful, please consider supporting the project:

Acknowledgments