Docs / Integrations

Integrations

What KLYRN VM connects to, and how. Each entry says what is built and tested, not what is planned.

IntegrationWhat it doesWhere
WHMCSCreate, suspend, unsuspend, terminate and change package from billingwhmcs/
TerraformMachines, networks and keys as codeterraform-provider-klyrn/
REST APIEverything the panel does, with scoped tokensvm.klyrn.com/docs/api/
Email notificationsMachine and node events to the people they concernSettings
WebhooksA signed POST for every audited action and finished taskSettings, Integrations
PowerDNSCustomers set reverse DNS for their own addresses; KLYRN publishes itSettings, Integrations
PrometheusThe whole estate as time series for Grafana and Alertmanagerbelow
SolusVM 2, Virtualizor, VMwareRead-only estate import, then adoptionMigration

Prometheus

GET /api/v1/metrics returns the estate in the Prometheus text format. Only an administrator may read it: create an API token for an administrator account with the Read everything scope and give it to Prometheus as a bearer token.

scrape_configs:
  - job_name: klyrn-vm
    scheme: https
    metrics_path: /api/v1/metrics
    authorization:
      type: Bearer
      credentials_file: /etc/prometheus/klyrn-vm.token
    static_configs:
      - targets: ['panel.example.com:8443']
MetricLabelsMeaning
klyrn_build_infoversionAlways 1; the running controller version
klyrn_vmsstateMachines running, stopped, needs_attention, creating, unknown
klyrn_vms_totalMachines in the estate
klyrn_node_upnode, node_id, state1 when a node is online or degraded and reporting
klyrn_node_memory_bytes, _allocated_bytes, _used_bytesnode, node_idManaged nodes only
klyrn_node_storage_bytes, _allocated_bytes, _used_bytesnode, node_idManaged nodes only
klyrn_node_cpu_threads, klyrn_node_vcpus_allocatednode, node_idManaged nodes only
klyrn_ipv4_free, klyrn_ipv4_totalAddresses across every pool
klyrn_tasks_running, klyrn_tasks_failed_24h, klyrn_tasks_waiting_nodeTask queue
klyrn_alerts_openseverityOpen alerts: fail, warn, info

Every figure is read from the same store queries as the Overview page, so a Grafana panel and the panel's own dashboard cannot disagree.

Alert rules worth starting with:

groups:
  - name: klyrn-vm
    rules:
      - alert: KlyrnNodeDown
        expr: klyrn_node_up == 0
        for: 5m
      - alert: KlyrnIPv4Low
        expr: klyrn_ipv4_free / klyrn_ipv4_total < 0.1
        for: 30m
      - alert: KlyrnStorageNearlyFull
        expr: klyrn_node_storage_used_bytes / klyrn_node_storage_bytes > 0.85
        for: 30m
      - alert: KlyrnTasksFailing
        expr: klyrn_tasks_failed_24h > 5

Webhooks

Settings, Integrations, Add webhook. Administrators only. Every action the Activity page records and every task that finishes is posted as JSON to each enabled webhook whose filter matches:

{"id":"evt_3f...","event":"vm.create","result":"ok","target":"vm:41",
 "actor":"admin@example.com","task_id":9001,"at":"2026-09-28T12:00:00Z",
 "controller":"panel.example.com"}
  • Filter: *, an exact code (vm.create), or a family (vm.*, node.*, backup.*). Codes are the ones in the Activity page.
  • Signature: X-Klyrn-Signature: t=<unix>,v1=<hex> where v1 is HMAC-SHA256 of t + "." + body with the secret shown once at creation. Reject a t older than five minutes.
  • Delivery: within a second, never blocking the action; retried after 2s and 10s on a network error, a 5xx, 408 or 429; switched off after 20 failures in a row. The last 100 attempts per hook, with the body and the answer, open from its row.
  • Refused destinations: link-local addresses such as the cloud metadata service 169.254.169.254, checked after DNS; redirects are not followed.

Verifying in Node:

const [t, v1] = sig.split(',').map((p) => p.split('=')[1])
const ok = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex') === v1
  && Date.now() / 1000 - Number(t) < 300

Reverse DNS (PowerDNS)

Settings, Integrations, Reverse DNS: the PowerDNS API address, its API key and server id (usually localhost). Test connection lists the server's zones and counts the reverse ones.

A customer sets a name on the machine's Networking tab, for an address allocated to that machine now, checked against the allocation table and never the request. KLYRN writes the PTR into the longest reverse zone on the server that contains it, so one zone per /24 and one per /16 both work without mapping. The zone itself is the provider's to create.

Every change is audited as vm.rdns, so a webhook on vm.* sees it. A PTR is kept even when no server is configured (shown as waiting) or the server refuses it (shown as not published, with the server's reason).

This page is generated from the guide that ships in the product's repository, so it describes the release it was built from. What changed in each release.