Observability
Date: 2026-06-22
Purpose
Section titled “Purpose”This guide describes what BetterNAT exposes for monitoring and debugging.
BetterNAT is decentralized. Each gateway node runs betternat-agent, owns its
local datapath reconciliation, and exposes local health data. There is no
central BetterNAT control server.
What You Can Observe
Section titled “What You Can Observe”BetterNAT is designed to answer these questions:
- Is the agent process running?
- Which node is active for an HA group?
- Is the HA status fresh?
- Does the DynamoDB lease match the local owner view?
- Does the Firestore lease match the local owner view on GCP?
- Do private route tables point to the expected active target?
- In stable egress IP mode, is the EIP associated with the expected owner?
- On GCP stable public identity, does the regional address point to the expected active gateway?
- Is the LoxiLB datapath ready?
- Are SNAT rule counters increasing?
- Are failover attempts and durations being recorded?
- Does a private client see the expected public egress IP?
Observability Surfaces
Section titled “Observability Surfaces”Terraform State And Outputs
Section titled “Terraform State And Outputs”The betternat_aws_gateway and betternat_gcp_gateway resources record
deployment state that is useful for runbooks and dashboards:
statuscontrol_plane_status_jsonmanaged_route_table_idsegress_public_ipsactive_instance_idsstandby_instance_idsrollback_route_targets_json
Use these outputs to locate the ASG or MIG, route tables or tagged route, active nodes, and expected public egress identity.
Example:
terraform output betternat_statusterraform output active_instance_idsterraform output standby_instance_idsterraform output egress_public_ipsLocal CLI
Section titled “Local CLI”Run CLI diagnostics on a gateway node when you need a live point-in-time view:
sudo betternat statussudo betternat doctor --liveUse the Operations Guide for the full CLI command list and command-by-command behavior. This guide focuses on the monitoring signals those commands expose.
Prometheus Metrics
Section titled “Prometheus Metrics”When prometheus_enabled = true, each node exposes:
http://<gateway-private-ip>:9108/metricsPrometheus should scrape every gateway node, not only the current active node. Standby metrics are important because they show whether failover capacity is actually ready.
Restrict access to the metrics port with security groups. It should be reachable from your monitoring network, not from the public internet.
For the disposable Quick Start, generate scrape targets from the ASG output:
export BETTERNAT_ASG_NAME="$( terraform -chdir=examples/terraform-aws-supplemental output -raw asg_name)"
export BETTERNAT_GATEWAY_INSTANCE_IDS="$( aws autoscaling describe-auto-scaling-groups \ --region "$AWS_REGION" \ --auto-scaling-group-names "$BETTERNAT_ASG_NAME" \ --query "AutoScalingGroups[0].Instances[].InstanceId" \ --output text)"
aws ec2 describe-instances \ --region "$AWS_REGION" \ --instance-ids $BETTERNAT_GATEWAY_INSTANCE_IDS \ --query "Reservations[].Instances[].PrivateIpAddress" \ --output text | tr '\t' '\n' | sed 's/$/:9108/'Minimal scrape job:
scrape_configs: - job_name: betternat static_configs: - targets: - 10.0.1.10:9108 - 10.0.1.11:9108In production, prefer EC2 service discovery filtered by the tags you pass to
betternat_aws_gateway, or generate scrape targets from Terraform outputs and ASG
membership.
Starter Prometheus alert rules are available at:
examples/prometheus/betternat-alerts.yamlStarter Grafana dashboard JSON is available at:
examples/grafana/betternat-starter-dashboard.jsonTreat both files as starting points. Tune alert durations, severity labels, dashboard variables, and routing labels to match your monitoring stack and incident policy.
Cloud Control Plane
Section titled “Cloud Control Plane”Use cloud APIs to cross-check what the agent reports. On AWS, inspect ASG membership, route table targets, EIP association, and DynamoDB lease state. On GCP, inspect MIG membership, tagged route target, regional address user, and Firestore-backed lease/handover state through gateway-local CLI. Exact commands live in the Operations Guide and GCP Checks.
Gateway Logs And Datapath State
Section titled “Gateway Logs And Datapath State”For local debugging, collect gateway logs and LoxiLB state from the node:
sudo systemctl status betternat-agent.servicesudo journalctl -u betternat-agent.service -n 200 --no-pagerloxicmd get firewall -o jsonloxicmd get conntrack -o jsonUse LoxiLB state for datapath-level debugging and Prometheus metrics for
alerting and historical trends. Use
betternat support bundle when you need a
redacted archive for incident review.
Key Metrics
Section titled “Key Metrics”Agent and HA:
betternat_agent_upbetternat_agent_build_infobetternat_activebetternat_ha_statebetternat_ha_status_age_secondsbetternat_ha_status_stalebetternat_lease_generationbetternat_lease_owner_matchbetternat_lease_seconds_until_expirybetternat_route_target_matchbetternat_public_identity_matchbetternat_takeover_attempts_totalbetternat_takeover_success_totalbetternat_lease_renew_errors_totalDatapath and traffic:
betternat_datapath_engine_infobetternat_datapath_readybetternat_conntrack_entriesbetternat_conntrack_udp_entriesbetternat_conntrack_establishedbetternat_loxilb_rule_presentbetternat_loxilb_rule_packets_totalbetternat_loxilb_rule_bytes_totalbetternat_owner_packets_totalbetternat_owner_bytes_totalbetternat_processed_packets_totalbetternat_processed_bytes_totalFailover:
betternat_failover_events_totalbetternat_failover_duration_secondsStarter Alerts
Section titled “Starter Alerts”Exactly one active node per HA group:
sum by (gateway, ha_group) (betternat_active) != 1Stale HA state:
betternat_ha_status_stale == 1Route does not match the expected active owner:
betternat_route_target_match == 0Stable public identity does not match the expected active owner:
betternat_public_identity_match == 0Datapath not ready:
betternat_datapath_ready == 0Lease renew errors:
increase(betternat_lease_renew_errors_total[5m]) > 0Repeated takeover attempts:
increase(betternat_takeover_attempts_total[15m]) > 1Takeover attempts without matching successes:
increase(betternat_takeover_attempts_total[15m]) - increase(betternat_takeover_success_total[15m]) > 0Recent failed lifecycle handover records are not currently a Prometheus metric. Check the durable records through the CLI:
betternat handover history --limit 20A failed termination-* handover record means the proactive ASG or Spot
termination path did not complete. Check whether betternat status, route
owner, EIP owner, and lease owner have still converged through normal lease
takeover before treating it as an active outage.
No traffic through a gateway that should be serving egress. Use this only for workloads that should have continuous traffic:
rate(betternat_processed_bytes_total[10m]) == 0Useful Queries
Section titled “Useful Queries”Current active owner:
betternat_active == 1Datapath engine in use:
betternat_datapath_engine_infoBytes by configured owner:
sum by (gateway, ha_group, owner) (rate(betternat_owner_bytes_total[5m]))SNAT rule packet rate by private CIDR:
sum by (gateway, ha_group, cidr) (rate(betternat_loxilb_rule_packets_total[5m]))Failover duration by phase:
betternat_failover_duration_secondsEgress IP Probe
Section titled “Egress IP Probe”Use a private-client synthetic probe to validate the full path from private workload to public internet:
curl -fsS https://checkip.amazonaws.comThis is a black-box complement to Prometheus. Mode-specific interpretation lives in the Operations Guide.
Attribution Scope
Section titled “Attribution Scope”BetterNAT can expose counters grouped by configured owner labels. This is useful when you map known private CIDR ranges to teams, node pools, or workload classes.
Current scope:
- owner attribution is configured explicitly in the agent config under
observability.attribution.owners, - each owner maps one or more private CIDRs to a stable
ownerlabel, - unmatched CIDRs are reported as
owner="unattributed", - exported owner metrics are aggregate counters:
betternat_owner_packets_total{owner, direction},betternat_owner_bytes_total{owner, direction},
- BetterNAT does not currently export automatic top-N source IP, destination IP, destination hostname, port, protocol, pod, namespace, or tenant labels.
Top owner throughput:
topk(10, sum by (gateway, ha_group, owner, direction) (rate(betternat_owner_bytes_total[5m])))Top owner packet rate:
topk(10, sum by (gateway, ha_group, owner, direction) (rate(betternat_owner_packets_total[5m])))Total processed throughput, without owner attribution:
sum by (gateway, ha_group, direction) (rate(betternat_processed_bytes_total[5m]))BetterNAT does not provide full Kubernetes pod-level attribution by itself. If private traffic comes from EKS nodes, BetterNAT normally sees node or VPC-level source addresses after the cluster networking layer. For pod-level attribution, combine BetterNAT gateway metrics with Kubernetes-side telemetry such as CNI flow logs, eBPF flow observability, application metrics, or VPC flow logs with ENI/IP metadata.
BetterNAT also does not provide exact per-tenant billing attribution, automatic source/destination cardinality analysis, or packet capture at scale.
Troubleshooting Patterns
Section titled “Troubleshooting Patterns”Metrics Endpoint Is Down
Section titled “Metrics Endpoint Is Down”Check:
betternat-agentservice status./etc/betternat/agent.jsonPrometheus listen address and port.- Local endpoint with
curl -fsS http://127.0.0.1:9108/metrics. - Security group ingress from the monitoring network.
- Prometheus target configuration.
Active Count Is Not One
Section titled “Active Count Is Not One”Check:
- whether all gateway nodes are being scraped,
betternat_ha_status_stale,betternat_lease_owner_match,betternat_route_target_match,betternat_public_identity_matchwhen stable EIP mode is enabled.
For operator-side investigation, use the Operations Guide troubleshooting sections for route/EIP mismatch, failed handover records, and datapath readiness.
Current Limits
Section titled “Current Limits”BetterNAT intentionally keeps observability local and simple:
- no central BetterNAT API server,
- no hosted BetterNAT dashboard or managed metric retention,
- no automatic fleet-wide CLI aggregation across accounts and regions,
- no built-in pod-level attribution,
- no long-term metric retention.
Use Prometheus, the starter dashboard, AWS APIs, and node-local CLI checks as the supported workflow.