ObservabilityLX · Network ObservabilityNetworkObs
Network Probes
What you'll learn
- Explain the role of synthetic probing in complementing white-box node and service metrics
- Configure blackbox_exporter icmp and tcp_connect modules to monitor external dependencies
- Choose a probe-source topology that does not collapse to a single egress point of failure
- Tune probe interval against scrape_timeout so that a slow probe does not race the scrape budget
- Decide when blackbox probing is sufficient and when the team needs a managed synthetic service
Prerequisites
Verified against Prometheus 2.55.x · Alertmanager 0.28.x · node_exporter 1.8.x · blackbox_exporter 0.26.x · Grafana 11.x · Loki 3.x · Tempo current · OpenTelemetry Collector 0.110.x · Grafana Alloy current · Docker Engine 28.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-13
The application is up. The node metrics are green. The customer in Frankfurt cannot reach it. The platform says everything is fine; the user says nothing works. The metric that resolves the disagreement is the one running on a host that is not in the data centre.
This is what synthetic probes are for. They are the platform’s external eyes.
What it is
Network probes, in this lesson, are synthetic checks issued by
blackbox_exporter from a controlled set of source locations
against a target set. The two probe families this lesson
covers:
- ICMP probes. A single ICMP echo request to a host. The
blackbox_exportericmpmodule requiresCAP_NET_RAWor root on the exporter host. The probe answers “is the host reachable at the IP layer?” - TCP probes. A single TCP
connect()to a host:port. Thetcp_connectmodule answers “is the port accepting connections?”
Both probes return probe_success (1 on success, 0 on
failure) and probe_duration_seconds (total wall-clock
duration of the probe including DNS resolution, connect, and
TLS if applicable). HTTP and DNS probes are covered in their
own lessons; the probe mechanics and topology discipline are
the same.
The canonical alternative is a managed synthetic service (Grafana Synthetic Monitoring, Pingdom, Catchpoint). The exporter is the right approach when the team already runs Prometheus and the probe sources can run as a small fleet of containers. The managed service is the right approach when the team needs probe sources in many geographies or from inside managed browsers.
Why a sysadmin cares
Three production failure classes disappear the day the probes are in place:
- Route blackouts. A peering session drops, a BGP route withdraws, a CDN edge goes offline. The application is up; the user-facing URL is not. Internal white-box metrics cannot see this. The probe that catches this is an HTTP probe from outside the application’s network (covered in the HTTP lesson).
- External dependency failure. A managed Postgres, an S3-compatible object store, a third-party API. The application is up; the dependency is not reachable from the production path. The probe that catches this is a TCP connect to the dependency’s port from a host that uses the same egress path.
- Silent configuration drift. A 503 that only manifests for one percent of users because a default backend fell out of a load-balancer pool at 02:00. The probe catches it within seconds because the probe path is the same path the user takes.
The probes are a load-bearing component of the observability platform. They are also small, run in single containers, and cost almost nothing in CPU. The reason to skip them is “we have internal monitoring.” The cost of skipping them is the next incident where the user is right and the internal panel is wrong.
How it works
The exporter exposes one HTTP handler, /probe. Prometheus
sends a request with two query parameters: target and
module. The exporter executes the probe, collects per-
protocol metrics, and returns them in Prometheus exposition
format.
prometheus.yml
|
v
scrape job: blackbox_icmp_external
|
| __param_target rewritten from __address__
| __param_module = icmp_router
|
v
blackbox_exporter :9115/probe?target=203.0.113.10&module=icmp_router
| ----- module: icmp_router ----
|
| ICMP echo request
| timeout 2s
|
v
probe_success 1
probe_duration_seconds 0.014
The scrape job drives the cadence. The exporter drives the protocol details. Prometheus stores the result alongside every other metric in the platform.
The ICMP module
The ICMP module opens a raw ICMP socket on the exporter host,
sends an echo request, and waits for the reply. The module
requires CAP_NET_RAW capability on the exporter container or
root on the host. Without the capability, the module fails to
initialise and the probe returns probe_success=0.
The module exposes the standard metrics:
probe_success—1if any reply was received within the timeout.probe_duration_seconds— wall-clock duration of the round-trip.probe_icmp_duration_seconds— the time spent waiting for the reply after sending the echo request.
The TCP connect module
The TCP module opens a TCP connection to target:port. No
application handshake. Success is a successful connect (the
three-way handshake completed). The module exposes:
probe_success—1if the connect succeeded.probe_duration_seconds— wall-clock duration including DNS resolution, connect, and any TLS if the target is HTTPS.
How to configure it
Three layers are required to put a probe into production: the exporter’s own config, the scrape job on Prometheus, and the relabeling layer that maps each probe target to a high- cardinality, low-cardinality label set.
1. The exporter config: blackbox.yml
# /etc/blackbox/blackbox.yml
modules:
# ICMP probe for host liveness. Requires CAP_NET_RAW.
icmp_router:
prober: icmp
timeout: 2s
icmp:
preferred_ip_protocol: ip4
ip_protocol_fallback: false
# ICMP probe for an external dependency.
icmp_dependency:
prober: icmp
timeout: 3s
icmp:
preferred_ip_protocol: ip4
ip_protocol_fallback: true
# TCP connect for database-port reachability.
tcp_connect_pg:
prober: tcp
timeout: 3s
# TCP connect for an HTTPS frontend (TLS is automatic).
tcp_connect_edge:
prober: tcp
timeout: 5s
# TCP connect for an internal service.
tcp_connect_internal:
prober: tcp
timeout: 2s
Each module is independent. A module can be reused by many
scrape jobs. Name the module after the question, not the
protocol: tcp_connect_pg is clearer than tcp1.
2. The scrape job
# /etc/prometheus/prometheus.yml
scrape_configs:
- job_name: blackbox_icmp_external
metrics_path: /probe
params:
module: [icmp_router]
scrape_interval: 30s
scrape_timeout: 10s
static_configs:
- targets:
- 203.0.113.10
- 203.0.113.11
- 198.51.100.5
labels:
service: external_dependency
env: prod
region: eu-west-1
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [service]
target_label: service
- target_label: module
replacement: icmp_router
- source_labels: [__address__]
regex: '(.*):(.*)'
replacement: '${1}'
target_label: instance
- job_name: blackbox_tcp_connect
metrics_path: /probe
params:
module: [tcp_connect_pg]
scrape_interval: 30s
scrape_timeout: 10s
static_configs:
- targets:
- pg-primary.internal:5432
- pg-replica.internal:5432
labels:
service: postgres
env: prod
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [service]
target_label: service
- target_label: module
replacement: tcp_connect_pg
- source_labels: [__address__]
regex: '(.*):(.*)'
replacement: '${1}'
target_label: instance
The pattern is the same as every other blackbox probe. The
__param_target rule rewrites the address; the module name is
stamped via replacement; the instance label is normalised.
3. Validation of the exporter config
# The exporter has no built-in check; the binary refuses to
# start with an invalid config, which is itself a check.
blackbox_exporter --config.check --config.file=/etc/blackbox/blackbox.yml
journalctl -u blackbox_exporter --since '5 min ago' | tail -20
# Validate the Prometheus side.
promtool check config /etc/prometheus/prometheus.yml
How to validate it
Three layers must be confirmed: the exporter is up, the scrape is flowing, and the probe actually exercises the path you think it does.
# 1. The exporter is up. Reads /metrics from the exporter,
# not from the probe.
curl -sf http://localhost:9115/metrics | grep -E '^blackbox_'
# blackbox_exporter_build_info{version="0.26.0"} 1
# blackbox_exporter_config_last_reload_successful 1
# blackbox_exporter_probe_total 18
# 2. Smoke-test the probe manually before trusting Prometheus.
curl -sf "http://localhost:9115/probe?module=icmp_router&target=203.0.113.10" \
| grep -E '^(probe_success|probe_duration_seconds)'
# probe_duration_seconds 0.014
# probe_success 1
# 3. Confirm Prometheus is receiving the series.
up{job="blackbox_icmp_external"}
# {instance="203.0.113.10", job="blackbox_icmp_external", service="external_dependency"} 1
probe_success{service="external_dependency"}
# 1
# 4. Confirm the exporter has CAP_NET_RAW for the ICMP module.
getcap /usr/bin/blackbox_exporter
# /usr/bin/blackbox_exporter cap_net_raw=ep
# Or, in a container:
docker inspect blackbox-exporter | jq '.[0].HostConfig.CapAdd'
# ["CAP_NET_RAW"]
# 5. The /-/ready endpoint of the exporter reports modules loaded.
curl -sf http://localhost:9115/-/ready
# ready
If probe_success is 1 and probe_duration_seconds is
non-zero, the probe is exercising the right path. If
probe_success is 0, inspect the exporter stderr log and
the relay metric for the underlying reason.
How it can fail
Six failure modes appear regularly. Each one is recognisable in the data.
-
ICMP blocked upstream. Many cloud providers and most corporate firewalls drop ICMP beyond the perimeter. The probe gets
probe_success=0for healthy hosts. Symptom:probe_success{module="icmp_router"}=0while every application-level probe is green. -
Single exporter host outage. Every probe is red at once. Symptom:
up{job="blackbox_*"}=0for the exporter itself; every target across every module is red. -
Module timeout shorter than the slowest legitimate response. A 2-second ICMP timeout on a 300 ms satellite link. The probe fires
for: 1mbefore the reply arrives. Symptom:probe_success=0withprobe_duration_secondsclose to the timeout value. -
CAP_NET_RAW missing. The ICMP module fails to initialise. Symptom: every ICMP probe returns
probe_success=0; the exporter log shows “operation not permitted” on socket open. -
TCP connect to a host that drops SYNs. A firewall drops SYNs silently (no RST). The probe times out. Symptom:
probe_success=0withprobe_duration_secondsclose to the timeout value. -
Probe target label cardinality. A scrape job against a thousand IPs with no labels produces a thousand series. The TSDB head block churns. Symptom: Prometheus memory rises;
prometheus_tsdb_head_seriesgrows.
How to troubleshoot it
Order matters. Start at the boundary where evidence is most concrete.
- Is the exporter alive?
curl http://exporter:9115/-/readyandcurl http://exporter:9115/metricsfirst. A missingblackbox_exporter_build_infoseries means the exporter is not running. - Does Prometheus see the exporter?
up{job="blackbox_*"}in PromQL. Ifup=0, the problem is at the scrape boundary, not at the target. - Does the probe itself work? Re-run the exact URL the
Prometheus scrape would produce, against the exporter
manually:
curl "http://exporter:9115/probe?module=...&target=...". The headers and body tell you which boundary failed. - Check
probe_duration_seconds. A drift from 14 ms to 4 s whileprobe_success=1is a brownout that has not yet failed. It precedes the failure. - Check the exporter host’s own egress. A
curlorpingfrom the exporter host to the target is the fastest test. - Compare modules against each other. If
tcp_connect_pgis green andicmp_dependencyis red on the same target, the failure is in ICMP filtering, not in reachability.
Security implications
The exporter accepts arbitrary target query parameters when
exposed without auth. That single endpoint, unauthenticated,
can be coerced into probing any IP or port the exporter host
can reach. In a multi-tenant environment that becomes a
port-scan primitive. Bind the exporter’s /probe to a network
Prometheus can reach but untrusted users cannot, or run it on
a private network.
The ICMP module requires CAP_NET_RAW on the host. The
capability is the same one that allows the host to send
arbitrary ICMP packets, including redirects and address-mask
requests that older kernels honour. A multi-tenant host that
grants CAP_NET_RAW to the exporter process is granting the
ability to spoof ICMP packets from that process’s UID. Use
the minimal capability set, and isolate the exporter in its
own container or VM.
The metric labels are produced by relabeling. A relabel rule that copies a user-controlled URL fragment into a label is a cardinality attack. Whitelist the labels.
Performance implications
The exporter is cheap per probe. The cost scales with the
cardinality of the instance and service label sets, the
scrape interval, and the time budget of the slowest legitimate
response.
- Probe interval. Default 30 s is reasonable. Faster intervals (5 s, 10 s) improve time-to-alert on outages but raise scrape load proportionally.
- Timeout. Each timeout is a goroutine held in the
exporter until the deadline. A misconfigured
timeout: 60son a hundred-target scrape job can occupy the exporter for the entire scrape interval. - Cardinality.
instance=hostplusservice=...plusmodule=...is the recommended minimum. Anything more, like full IPs in labels, is a budget problem. - Timeouts and the scrape budget.
scrape_timeouton Prometheus must be longer than any module’s timeout. A module withtimeout: 5sscraped every 30 s withscrape_timeout: 5sraces against the exporter.
Production guidance
- Run at least two probe sources in different failure domains. A common topology is one exporter per region, per cloud provider, or per egress point.
- Pin the module names that alerts and dashboards reference. Renaming a module without coordinating dashboards and alerts is the same class of break as renaming a node_exporter metric on a hundred hosts at once.
- Use a separate scrape job per target class. Do not lump external dependencies and internal services into one job; the failure modes and the alert routing differ.
- Validate the exporter config with
--config.check. Validate the Prometheus side withpromtool check config. Both must pass before the change ships. - Document the ICMP permission model.
CAP_NET_RAWis not a capability to grant lightly. Run the exporter with the minimum capability set, ideally in a container with the capability dropped.
Verification
You should now be able to answer:
- What is the operational difference between an ICMP probe and a TCP connect probe?
- Why is a single exporter host a single point of failure for synthetic probes?
- Which capability does the ICMP module require, and how is it set on a containerised exporter?
- How do you decide between a 30-second probe interval and a 10-second interval?
- What is the trade-off between blackbox_exporter and a managed synthetic service?
Quiz
Knowledge check · 8 questions
Q1. Which capability does the blackbox_exporter ICMP module require?
Q2. A single probe exporter host is a smell because:
Q3. A 60-second probe interval and a 5-second scrape_timeout with a module timeout of 8 seconds races against the scrape budget.
Q4. ICMP probes to one dependency return probe_success 0 while the TCP connect probe to the same host returns 1. The likely cause is:
Q5. Which PromQL expression gives the average probe duration over five minutes across all targets in a job?
Q6. Which of these are valid reasons to use a managed synthetic service over blackbox_exporter? Select all that apply.
Q7. probe_duration_seconds drifts from 14 ms to 4 s while probe_success remains 1. What does this mean?
Q8. The exporter endpoint /probe is bound on the public internet. The likely abuse vector is:
Passing score: 75%. Answers are checked in this browser.