XMS Observability Stack
Overview
The XMS Observability Stack provides monitoring, logging, and visualization for the XoT Management System (XMS) and its connected devices. It combines Prometheus (metrics), Loki (log aggregation), and Grafana (dashboards) to give operators a unified view of system health.

With this stack, XMS administrators can:
- Monitor real-time health and performance of XMS infrastructure.
- Analyze trends and identify potential bottlenecks before they impact service.
- Troubleshoot issues by correlating metrics and logs from various XMS components.
- Gain visibility into the status and activity of devices managed by XMS.
Prerequisites
| Requirement | Details |
|---|---|
| Operating System | Ubuntu (Noble or Jammy) |
| Docker & Docker Compose | Required for Docker Compose deployment |
| DNS entries | web.grafana.<DOMAIN>, grafana.<DOMAIN>, loki.<DOMAIN>, prom.<DOMAIN> |
| SSL certificates | Let's Encrypt (recommended) or self-signed (auto-generated for development) |
Deployment
Choose one of the two deployment options below.
Option A: Docker Compose
- Clone or extract the repository
Clone the XMS Observability repo, or expand the compressed copy from here into an appropriate location (e.g., /opt/ or /srv/).
- Configure environment variables
cp .env.example .env
Edit .env with your domain and credentials. By default, subdomains are web.grafana, grafana, loki, and prom. To customize, set prefix overrides in .env (e.g., LOKI_PREFIX=logs produces logs.<DOMAIN>).
- Generate configuration files
./scripts/init.sh
This reads .env and generates grafana.ini and nginx.conf.d/service.conf from their .template files. Re-run this script whenever you change .env.
init.sh also auto-generates htpasswd from BASIC_AUTH_USER and BASIC_AUTH_PASSWORD in .env. To regenerate manually, delete the existing file and re-run init.sh, or use htpasswd directly (apache2-utils required). These credentials are used in the FluentBit Loki and Prometheus configs on XMS servers.
For development, init.sh auto-generates self-signed certificates if none exist at credentials/fullchain.pem and credentials/privkey.pem.
- Start the stack
sudo docker compose up -d
Option B: Debian Package
The Debian package installs the stack to /opt/xms-observability/ with systemd integration.
- Install the package
Download from https://xertpubrepo.blob.core.windows.net/v38/xms-observability-*.deb and install like this:
sudo apt install ./xms-observability_*.deb
The installer collects configuration values via interactive debconf prompts, generates configs from templates via envsubst, creates htpasswd, generates self-signed certs if needed, and enables a systemd service.
- Service management
systemctl status xms-observability
systemctl restart xms-observability
systemctl stop xms-observability
Post-Deployment Configuration
SSL with Let's Encrypt
For production deployments, Let's Encrypt is strongly recommended over self-signed certificates.
- Obtain certificates — Run the automated setup script:
sudo ./scripts/setup-certbot.sh
This obtains certificates via certbot with webroot challenge mode and copies them into credentials/. The port 80 Nginx server block serves ACME challenge tokens from /var/www/certbot/ before redirecting other traffic to HTTPS.
Note: If you already have certificates, you can skip this step and place them manually at
credentials/fullchain.pemandcredentials/privkey.pem.
- Verify certificates are in place — Confirm both files exist:
ls -l credentials/fullchain.pem credentials/privkey.pem
- Automatic renewal — The setup script installs a deploy hook for automatic renewal via
certbot.timer. Verify the timer is active:
systemctl status certbot.timer
Keycloak OAuth2 (Optional)
OAuth is disabled by default. To enable it, first create a client in XMS Keycloak (e.g., https://xms.<DOMAIN>/idp), under Realm XMS > Clients > Create Client.
Client Settings
| Field | Value |
|---|---|
| Client ID | grafana-oauth (or similar) |
| Name | Grafana Client (free text) |
| Description | (can be empty) |
| Client authentication | On |
| Authorization | Off |
| Standard Flow | Enabled |
| Direct Access Grants | Enabled |
| Root URL | https://web.grafana.<DOMAIN>/ |
| Home URL | (empty) |
| Valid redirect URIs | https://web.grafana.<DOMAIN>/login/generic_oauth |
| Valid logout URIs | (empty) |
| Web origins | https://web.grafana.<DOMAIN>/ |
| Admin URL | https://web.grafana.<DOMAIN>/ |
After creating the client:
-
Generate a client secret in the Credentials tab.
-
In Client Scopes, assign
none. -
Run the setup script:
./scripts/setup-oauth.sh
The script prompts for Keycloak URL, client ID, and client secret, then updates .env and regenerates grafana.ini. It can be re-run at any time to reconfigure or disable OAuth (--disable flag).
XMS Integration
This section covers configuration on the XMS servers that send data to the observability stack.
Environment Variables
Add the following to the XMS server's .env file:
GRAFANA_ENABLED=true
GRAFANA_URL=https://web.grafana.<DOMAIN>/d/
GRAFANA_ENVIRONMENT=<hostname>
GRAFANA_XOT_DASHBOARD_PATH=b0167a72-3cc2-4eee-99aa-0a53f06e61a1/individual-xot-dashboard
| Variable | Description |
|---|---|
GRAFANA_ENABLED |
Enables the Grafana integration in the XMS web interface. |
GRAFANA_URL |
Base URL for Grafana dashboard links. |
GRAFANA_ENVIRONMENT |
A label identifying this XMS instance (typically the output of hostname). Used to filter dashboards by environment. |
GRAFANA_XOT_DASHBOARD_PATH |
Path to the individual XoT device dashboard in Grafana. |
Restart XMS to apply the changes:
sudo systemctl restart xms
FluentBit Setup
- Add the GPG key
curl https://packages.fluentbit.io/fluentbit.key | gpg --dearmor | sudo tee /usr/share/keyrings/fluentbit-keyring.gpg > /dev/null
- Add the APT repository
Add the following to /etc/apt/sources.list.d/fluentbit.list, replacing ${CODENAME} with noble or jammy:
deb [signed-by=/usr/share/keyrings/fluentbit-keyring.gpg] https://packages.fluentbit.io/ubuntu/${CODENAME} ${CODENAME} main
- Install FluentBit
sudo apt update && sudo apt install fluent-bit
- Configure FluentBit for XMS
Replace the default config to include XMS logging configuration:
sudo cp /etc/fluent-bit/fluent-bit.conf /etc/fluent-bit/fluent-bit.conf.bak
echo '@INCLUDE /etc/xms/config/logging/fluent-bit.conf' | sudo tee /etc/fluent-bit/fluent-bit.conf
- Start the service
sudo systemctl enable --now fluent-bit
- TLS verification settings
If using self-signed certificates, set tls.verify to off in:
/etc/xms/config/logging/prometheus.conf/etc/xms/config/logging/loki.conf
Warning: Disabling TLS verification removes certificate validation. This is acceptable for development but should be avoided in production. Use Let's Encrypt certificates for production deployments.
If using Let's Encrypt certificates, no changes are needed — tls.verify can remain on.
Verification
After completing deployment and XMS integration, verify that the stack is working correctly:
- Check that all services are running
sudo docker compose ps # Docker Compose deployment
systemctl status xms-observability # Debian package deployment
-
Access Grafana — Navigate to
https://web.grafana.<DOMAIN>/and log in with the credentials configured in.env. -
Confirm Prometheus targets — In Grafana, go to the Prometheus data source and verify that XMS targets are listed and in an
UPstate. -
Verify logs in Loki — Use the Explore view in Grafana with the Loki data source to confirm logs are being received from the XMS servers.
-
Check the XMS web interface — Open the diagnostics page for any device in XMS. A Grafana button should appear linking to the device's dashboard.
Troubleshooting
| Symptom | Possible Cause | Resolution |
|---|---|---|
| Grafana is not accessible | Nginx misconfiguration or DNS not resolving | Verify DNS entries resolve correctly. Check Nginx logs: sudo docker compose logs nginx |
Prometheus targets show DOWN |
FluentBit not running or wrong basic auth credentials | Verify FluentBit is running (systemctl status fluent-bit). Confirm BASIC_AUTH_USER/BASIC_AUTH_PASSWORD in .env match the FluentBit config. |
| No logs appearing in Loki | FluentBit misconfigured or TLS verification failing | Check FluentBit logs: journalctl -u fluent-bit. If using self-signed certs, ensure tls.verify is set to off in the Loki output config. |
| Grafana button missing in XMS | Environment variables not applied | Confirm GRAFANA_ENABLED=true is set in the XMS .env file and restart XMS: sudo systemctl restart xms. |
| OAuth login fails | Keycloak client misconfiguration | Verify redirect URIs and client secret match. Re-run ./scripts/setup-oauth.sh to reconfigure. |
| Certificate renewal not working | Certbot timer not active | Check timer status: systemctl status certbot.timer. Verify the webroot path /var/www/certbot/ is accessible on port 80. |