Prometheus & Grafana

Node64 exposes its metrics at /api/metrics in the Prometheus text format – from the core through health checks, DynDNS, DNS64, PROXY64 and CDN64 to certificates. Plug your node into your existing monitoring, build Grafana dashboards and write your own alerting rules.

Overview

WhatValue
EndpointGET /api/metrics
FormatPrometheus text format 0.0.4 (text/plain; version=0.0.4), never cached
AuthenticationAPI key as bearer token (or a browser session)
Contentsthe core and every running module; disabled modules only report node64_module_running{module="…"} 0
Durationa few milliseconds per scrape
Interval15 to 60 seconds works well

Setup

  1. Under the API menu item (/api/docs, section API keys), create a dedicated key, for example named prometheus. More in Local API.
  2. Save the key on your Prometheus server in a file such as /etc/prometheus/node64.key. The file contains nothing but the key (node64_…).
  3. Add a scrape job to your prometheus.yml and reload Prometheus.
prometheus.yml
scrape_configs:
  - job_name: node64
    scheme: https            # or http, depending on how you open the web interface
    metrics_path: /api/metrics
    authorization:
      type: Bearer
      credentials_file: /etc/prometheus/node64.key   # contains: node64_...
    tls_config:
      insecure_skip_verify: true   # only with the web interface's self-signed certificate
    static_configs:
      - targets: ["node64.lan:8080"]

Node64 speaks HTTP and HTTPS on the same port. If the web interface has a proper certificate (see Certificates), drop insecure_skip_verify. Every node has its own API keys, so for several nodes create one scrape job per node, each with its own key file.

Quick manual test:

bash
curl -s -H "Authorization: Bearer $(cat node64.key)" http://node64.lan:8080/api/metrics | head

Authentication and protection

  • /api/metrics is protected like the rest of the API: without a key you get 401.
  • Every scrape updates the key's "last used" – so the key list tells you whether Prometheus is still scraping.
  • Node64 slows down invalid keys just like for the rest of the API (after 5 failed attempts, only one attempt every 30 seconds).
  • Use a key just for Prometheus. If you no longer need it, delete it without breaking any other scripts.

All metrics

Points in time are Unix time in seconds (suffix _seconds), durations are in seconds, data volumes in bytes. Metrics that are "always 1" carry their information in a label – count them with count or sum.

Core

MetricTypeLabelsMeaning
node64_infoGaugeversion, node_id, node_name, hostnamealways 1
node64_start_time_secondsGaugeprocess start time
node64_uptime_secondsGaugetime since start
node64_database_bytesGaugedatabase size including WAL
node64_module_enabledGaugemodule1 = enabled in the settings
node64_module_runningGaugemodule1 = module is running
node64_module_errorGaugemodule1 = module reports an error
node64_module_infoGaugemodule, versionalways 1, module version
node64_link_linkedGauge1 = linked to an ipv64.net account (health checks sync)
node64_link_connectedGauge1 = connection to ipv64.net is up
node64_link_outboxGaugeentries not yet transferred
node64_link_conflictsGaugeopen conflicts
node64_link_last_sync_secondsGaugelast successful sync
node64_link_online_checks_todayGaugeonline measurements used today (linked only)
node64_link_online_checks_limitGaugedaily limit of online measurements, 0 = none (linked only)
node64_group_membersGaugemembers of the cluster (excluding this node)
node64_group_members_onlineGaugeof which reachable
node64_group_member_upGaugenode_id, node_name1 = member reachable
node64_mcp_enabledGauge1 = AI interface (MCP) switched on
node64_mcp_calls_totalCountertool, resulttool calls via MCP since start, result = ok or error
go_goroutinesGaugenumber of goroutines
go_memstats_heap_alloc_bytesGaugeallocated heap
go_memstats_sys_bytesGaugememory obtained from the operating system
go_gc_cycles_totalCountercompleted garbage collection cycles
node64_scrape_duration_secondsGaugeduration of this scrape

Health checks

Labels per check: token (stays the same even if the name changes), check (name), type and group.

MetricTypeLabelsMeaning
node64_hc_check_stateGaugecheck, statealways 1, state in the label: up, down, degraded, flapping, dependent, stabilizing, paused, pending, unchecked
node64_hc_check_upGaugecheck1 = reachable (up, degraded), 0 = down; missing when paused, pending or unchecked
node64_hc_check_maintenanceGaugecheck1 = currently in maintenance
node64_hc_check_last_secondsGaugechecktime of the last measurement
node64_hc_check_latency_secondsGaugecheckresponse time of the last measurement
node64_hc_check_consecutive_failuresGaugecheckconsecutive failures
node64_hc_check_interval_secondsGaugecheckcheck interval
node64_hc_check_cert_expiry_secondsGaugecheckTLS certificate expiry (HTTPS checks only)
node64_hc_checksGaugestatenumber of checks per state; maintenance is counted additionally
node64_hc_incidents_openGaugeopen incidents

Proxmox VE

Per system (system), node and guest: node64_pve_up, node64_pve_error, node64_pve_poll_failures_total, node64_pve_quorate, node64_pve_guests_running, node64_pve_guests_bad, node64_pve_node_up, node64_pve_guest_state, node64_pve_guest_up plus CPU, RAM and disk as a ratio 0..1 (node64_pve_node_*_ratio, node64_pve_guest_*_ratio), and per guest network and disk I/O in bytes/s (node64_pve_guest_net_*_bytes, node64_pve_guest_disk_*_bytes), RAM in bytes and CPUs (node64_pve_guest_memory_bytes, node64_pve_guest_cpus). The full list is under Proxmox VE.

Docker

For Docker monitoring. Per host: node64_docker_up, node64_docker_enabled, node64_docker_poll_failures_total, node64_docker_last_poll_seconds, node64_docker_containers_running, node64_docker_containers_bad. Per container: node64_docker_container_state{state,detail}, …_container_up, …_container_restarts, …_container_cpu_ratio, …_container_cpus, …_container_memory_ratio, …_container_memory_bytes, …_container_memory_limit_bytes, …_container_uptime_seconds, …_container_net_in_bytes, …_container_net_out_bytes, …_container_disk_read_bytes and …_container_disk_write_bytes.

DynDNS

MetricTypeLabelsMeaning
node64_dyndns_target_statusGaugetarget, statusalways 1, state in the label: ok, cdn, pending, dns, error, paused, off, new
node64_dyndns_target_okGaugetarget1 = last update succeeded, 0 = error; missing when off, paused or new
node64_dyndns_target_last_ok_secondsGaugetargetlast successful update
node64_dyndns_target_last_error_secondsGaugetargetlast error
node64_dyndns_targetsGaugestatusnumber of targets per state
node64_dyndns_updates_24hGaugecalls to ipv64.net in the last 24 hours

DNS64

The counters run since the DNS server last started. Changing the settings restarts it – rate() and increase() handle that just fine.

MetricTypeLabelsMeaning
node64_dns64_upGauge1 = DNS server running
node64_dns64_start_time_secondsGaugestart of the DNS server
node64_dns64_blocking_pausedGauge1 = blocking paused
node64_dns64_queries_totalCounterstatus, protoqueries; status: allowed, cached, blocked, local, error, custom; proto: udp, tcp, doh, dot, doq
node64_dns64_query_duration_seconds_sum, …_countCountersum and count of response times (average via rate(sum)/rate(count))
node64_dns64_querylog_dropped_totalCounterentries not written to the query log
node64_dns64_refused_totalCounterrefused because they came from outside the allowed networks
node64_dns64_blocklist_domainsGaugedomains in the blocklists
node64_dns64_cache_entries, node64_dns64_cache_max_entriesGaugeentries in the cache and its size
node64_dns64_cache_hits_total, …_misses_total, …_stale_served_totalCountercache hits, misses and answers served stale
node64_dns64_upstream_upGaugeupstream, proto1 = upstream healthy
node64_dns64_upstream_requests_total, node64_dns64_upstream_errors_totalCounterupstream, protorequests to the upstream and errors
node64_dns64_upstream_latency_secondsGaugeupstream, protoaverage upstream response time
node64_dns64_group_queries_totalCountergroup, statusqueries per device group and result
node64_dns64_group_internet_offGaugegroup1 = internet off for the group (button or schedule)
node64_dns64_group_freeGaugegroup1 = "Free" button active (schedules and categories suspended)
node64_dns64_group_membersGaugegroupentries (MAC, IP, network) of the group
node64_dns64_forward_upGaugedomain, serverforward server healthy (1/0)
node64_dns64_forward_requests_totalCounterdomain, serverrequests to the forward server
node64_dns64_forward_errors_totalCounterdomain, servererrors of the forward server

PROXY64 and CDN64

Labels per host: host_id (stays the same), host (first name) and kind (proxy, redirect, dead, passthrough).

MetricTypeLabelsMeaning
node64_cdn64_hostsGaugenumber of hosts
node64_cdn64_host_enabledGaugehost1 = enabled
node64_cdn64_host_requests_totalCounterhostrequests since the node started
node64_cdn64_host_errors_totalCounterhosterrors (5xx, target unreachable) since start
node64_cdn64_host_blocked_totalCounterhostrejected requests since start
node64_cdn64_host_requests_24hGaugehost, status (2xx … 5xx)requests in the last 24 hours per status class
node64_cdn64_host_bytes_24hGaugehostbytes sent in the last 24 hours
node64_cdn64_host_blocked_24hGaugehostrejected requests in the last 24 hours
node64_cdn64_host_target_upGaugehost1 = target reachable at the last check (proxy and TLS passthrough only)
node64_cdn64_host_target_latency_secondsGaugehostconnect time to the target
node64_cdn64_honeypot_blocks, …_blocks_total, …_rejected_total, …_decoy_total, …_reported_totalGauge, Counterworking with Honeypot64: active instant blocks, blocks, rejections, requests passed to the bait and reported (only when a switch is on)

CDN64 – these values come from the node's last sync with ipv64 (every minute):

MetricTypeLabelsMeaning
node64_cdn64_online_nameGaugehost_id, name, modealways 1: name is enabled online (mode 1 = passthrough, 2 = terminate)
node64_cdn64_online_edge_connectedGaugeedge1 = tunnel to this edge server connected
node64_cdn64_online_edge_rtt_secondsGaugeedge, transport (quic, tcp)round-trip time of the tunnel
node64_cdn64_online_edge_streamsGaugeedgeopen visitor streams
node64_cdn64_online_edge_streams_total, …_reconnects_totalCounteredgestreams and reconnects since the node started
node64_cdn64_online_host_statusGaugename, mode, statusalways 1, state at ipv64: active, pending, blocked
node64_cdn64_online_host_traffic_month_bytesGaugenametraffic of this name in the current month
node64_cdn64_online_domains_used, …_domains_limitGaugeCDN domains of the account (the classic ipv64 CDN counts too)
node64_cdn64_online_traffic_used_bytes, …_traffic_limit_bytesGaugeCDN traffic of the account this month and its quota
node64_cdn64_online_last_sync_secondsGaugelast sync with ipv64
node64_cdn64_online_sync_okGauge1 = the last sync succeeded

Certificates

The values of the central certificate management belong to the core and are always included. Labels per certificate: cert_id, name (first name) and source (ipv64, alias, http, dns, ca, self, upload).

MetricTypeLabelsMeaning
node64_certsGaugenumber of certificates
node64_cert_expiry_secondsGaugecertificateexpiry time
node64_cert_statusGaugecertificate, statusalways 1, state in the label: pending, valid, error, expired
node64_cert_errorGaugecertificate1 = last issuance or renewal failed
node64_cert_auto_renewGaugecertificate1 = renewed automatically

Honeypot64

Only with the module switched on; details under Honeypot64.

MetricTypeLabelsMeaning
node64_honeypot_connections_totalCounterservice, portconnections to the trap services
node64_honeypot_logins_totalCounterservicelogin attempts
node64_honeypot_events_totalCounterkind, sourceevents per kind
node64_honeypot_unique_sourcesGaugedistinct source IPs of the last 24 hours
node64_honeypot_listen_errorsGaugeportport could not be opened
node64_honeypot_buffer_events, node64_honeypot_dropped_totalGauge, Counterevents in the buffer, dropped due to overload
node64_honeypot_report_last_success_timestampGaugelast successful report to ipv64 (Unix time, 0 = none yet)
node64_honeypot_report_errors_total, node64_honeypot_report_sources_totalCounterfailed reports, reported source IPs
node64_honeypot_log_lines_total, node64_honeypot_log_file_okCounter, Gaugepathlog lines read; file is being read (1) or error (0)
node64_honeypot_syslog_messages_total, node64_honeypot_syslog_denied_totalCounteraccepted and rejected syslog messages
node64_firewall_active, node64_firewall_entries, node64_firewall_list_entriesGaugefamily or list, editionfirewall helper in the mode without a web interface: active, entries per address family and list
node64_firewall_last_update_timestamp, node64_firewall_errors_totalGauge, Counterlast update, errors
node64_honeypot_proxy_decoy_total, …_proxy_access_total, …_proxy_access_dropped_total, …_proxy_blocks_totalCounterworking with PROXY64: bait requests, analysed and dropped accesses, instant blocks
node64_honeypot_events_by_country_totalCountercountryevents per country of origin

Example alerting rules

You can drop these rules straight into a Prometheus rule file and route them through Alertmanager. Adjust thresholds and wait times (for) to your setup.

node64-rules.yml
groups:
  - name: node64
    rules:
      - alert: Node64Down
        expr: up{job="node64"} == 0
        for: 5m
        annotations:
          summary: "Node64 {{ $labels.instance }} is not responding"
      - alert: Node64ModuleError
        expr: node64_module_error == 1
        for: 10m
        annotations:
          summary: "Module {{ $labels.module }} reports an error"
      - alert: Node64CheckDown
        expr: node64_hc_check_up == 0 and on(token) node64_hc_check_maintenance == 0
        for: 2m
        annotations:
          summary: "{{ $labels.check }} is down"
      - alert: Node64CertExpiresSoon
        expr: node64_hc_check_cert_expiry_seconds - time() < 14 * 86400
        annotations:
          summary: "Certificate of {{ $labels.check }} expires in less than 14 days"
      - alert: Node64DynDNSError
        expr: node64_dyndns_target_ok == 0
        for: 15m
      - alert: Node64DNSUpstreamDown
        expr: node64_dns64_upstream_up == 0
        for: 5m
      - alert: Node64CertExpires
        expr: node64_cert_expiry_seconds - time() < 14 * 86400 and on(cert_id) node64_cert_auto_renew == 1
        annotations:
          summary: "Certificate {{ $labels.name }} expires in less than 14 days (renewal failing?)"
      - alert: Node64CDN64TargetDown
        expr: node64_cdn64_host_target_up == 0 and on(host_id) node64_cdn64_host_enabled == 1
        for: 5m
      - alert: Node64CDN64TunnelDown
        expr: node64_cdn64_online_edge_connected == 0
        for: 3m
      - alert: Node64IPv64Disconnected
        expr: node64_link_linked == 1 and node64_link_connected == 0
        for: 10m
Avoid duplicate alerts

Node64 already notifies you about outages through its own notification channels. Prometheus alerts are most useful if you want everything in one place – or as a second, independent view of the node itself (such as Node64Down).

Grafana

Grafana doesn't need a separate interface: it reads the values from Prometheus.

  1. In Grafana, go to Connections → Data sources, add a data source of type Prometheus and enter the address of your Prometheus server.
  2. Create a new dashboard and add panels with the queries below.
  3. Optionally add a variable for several nodes, for example with label_values(node64_info, node_name).

There's no ready-made dashboard template – but with these queries you'll have your own dashboard up in no time:

PanelPromQL
Checks down (stat)sum(node64_hc_checks{state="down"})
Response time per check in msnode64_hc_check_latency_seconds * 1000
Open incidentsnode64_hc_incidents_open
Days until certificate expiry(node64_cert_expiry_seconds - time()) / 86400
DNS queries per second by statussum by (status) (rate(node64_dns64_queries_total[5m]))
Share of blocked DNS queries (1 h)sum(increase(node64_dns64_queries_total{status="blocked"}[1h])) / sum(increase(node64_dns64_queries_total[1h]))
Average DNS response timerate(node64_dns64_query_duration_seconds_sum[5m]) / rate(node64_dns64_query_duration_seconds_count[5m])
DNS cache hit raterate(node64_dns64_cache_hits_total[5m]) / (rate(node64_dns64_cache_hits_total[5m]) + rate(node64_dns64_cache_misses_total[5m]))
Reverse proxy: requests per second per hostsum by (host) (rate(node64_cdn64_host_requests_total[5m]))
Reverse proxy: error rate per hostsum by (host) (rate(node64_cdn64_host_errors_total[5m])) / sum by (host) (rate(node64_cdn64_host_requests_total[5m]))
Node uptime in daysnode64_uptime_seconds / 86400
Node memorygo_memstats_sys_bytes

If your node is linked, you'll also find the results of online checks from Nuremberg and Falkenstein in the ipv64.net portal.

Something unclear, missing, or a question about Node64? Ask in the official forum v64.tech.

Questions about Node64?
For any questions about the product, use the official forum: setup, troubleshooting, ideas and exchange with the community and the ipv64.net team.
Go to the forum v64.tech