Skip to main content

HTTP Check

Pull

Synopsis​

Director requests one URL over HTTP or HTTPS from where it runs, as a client would, and writes the result of every check itself as an ECS document: its status code, its timings, its TLS certificate, whether its body holds a text, and the state the service is in — up or down, since when, and after how many checks. Nothing is installed on the service.

The HTTP Check is one of six service check devices, each checking one service: a Website, an HTTP Check, a TCP Check, a DNS Check, an ICMP Check, and a TLS Check. It is a client: the HTTP device is a listener, which binds a port and receives what is sent to it.

One device, one service. A device checks one URL, so every service checked has a row of its own in the fleet list, and the device's connection state says whether that service is up. A check that fails for one service does not hide behind one that succeeds.

The results are the device's own. Every check writes a result, up or down, with no dataset assigned: the results reach routes and pipelines as a listener's records do. An HTTP Check has no datasets: every result carries the service's certificate and the certificate of its chain that expires first. See Service Check Datasets.

The device dials the service and binds nothing, so service checks never collide on a port. One Director owns each device: two would check the same service twice, and count every check of it twice.

note

The service check devices need Director 2.2.3 or later.

Schema​

- id: <numeric>
name: <string>
description: <string>
type: http_check
tags: <string[]>
status: <boolean>
properties:
url: <string>
method: <string>
expected_status: <numeric[]>
body_match: <string>
follow_redirects: <boolean>
username: <string>
password: <string>
headers: <map>
tls:
status: <boolean>
insecure_skip_verify: <boolean>
ca_name: <string>
server_name: <string>
min_tls_version: <string>
max_tls_version: <string>
interval: <numeric>
timeout: <numeric>
pipelines: <pipeline[]>

Configuration​

The following fields are used to define the device:

Device​

FieldRequiredDefaultDescription
idY-Unique numeric identifier
nameY-Device name
descriptionN-Optional description
typeY-Must be http_check
tagsN-Optional tags
statusNtrueEnable/disable the device

Request​

FieldRequiredDefaultDescription
urlY-http:// or https://, with a host that is not a wildcard. A URL that carries user:password@ is refused: set username and password instead. An IPv6 host is written in one pair of brackets
methodNGETGET, or HEAD, which reads no body
expected_statusNany 2xxA status code, or a list of them, that mean up
body_matchN-A text the body must hold. The body is read to its end, or to 10 MiB, and searched as it streams. Refused beside HEAD
follow_redirectsNtrueFollows up to 10 redirects and reads the last answer; false reads the redirect itself

Credentials​

FieldRequiredDefaultDescription
username, passwordN-Sent as basic authentication. Plain text, ${ENV_VAR}, or $secret{...}
headersN-A map of header names to values, each plain text, ${ENV_VAR}, or $secret{...}. Host follows the URL, and Authorization is basic authentication's while username is set

The credentials and the headers are resolved at every check, so a password rotated in a vault is sent once the vault's cache lets it through. The configuration keeps the reference, and a changed reference restarts the device. A credential that does not resolve fails the check with Configuration error, and no request is sent.

They go to the URL's own origin alone: its scheme, host, and port. A redirect anywhere else gets neither the basic authentication nor the headers — including a redirect from https:// to http:// on the same host, which would send them in cleartext, and one to another port of the host.

A query parameter whose name looks like a credential (api_key, token, sig, password, ...) is masked in every record and message. The API withholds the password and every header's value from its device reads.

warning

An http:// URL sends the username, the password, and every header in cleartext. The device says so in its log when it starts. Use one only where the network between the Director and the service is trusted.

TLS​

FieldRequiredDefaultDescription
tls.statusNthe URL'strue for https://, false for http://. When given, it has to agree with the URL
tls.insecure_skip_verifyNfalsetrue accepts any certificate, and still writes its expiry. Pin the CA instead where you can
tls.ca_nameN-A CA to verify the certificate against instead of the operating system's trust store: a path under the service root, or inline PEM
tls.server_nameN-The name the certificate is verified for, when it is not the URL's host
tls.min_tls_versionNtls1.2tls1.0 to tls1.3
tls.max_tls_versionN-No cap

The TLS settings verify the URL's certificate and that of any https:// URL a redirect leads to. A certificate that does not verify fails the check with Certificate error, and is still written: its dates, its names, and its days left, the fields an expiring certificate is watched by. The result also names the certificate of the chain that expires first, and its days left — an expiring intermediate breaks the site as surely as the service's own certificate does.

Pipeline​

The device takes at most one pre-processing pipeline of its own: the device's pipeline picker in the console, pipelines: in a configuration file. Its results go through it, and through none when the device has none.

Datasets​

An HTTP Check has no datasets: it writes its results directly. Every result for an https:// URL carries the service's certificate under tls.server.x509.*, its days left, and the certificate of its chain that expires first (see Results and State), so the HTTP Check Certificates dataset is retired; and Traceroute is a website's dataset alone. A dataset still assigned to the device is left out with a warning in the device's log — see Retired Datasets.

Advanced Configuration​

FieldRequiredDefaultDescription
intervalN60Seconds between checks: a result every interval. At least 10
timeoutN10Seconds a request may take, its body included, from 1 to 120

A configuration error — no URL, a URL that carries credentials, a CA that cannot be read, an interval under its floor — stops the device with Configuration error. The message names the property, never its value. A number is read whole: a fraction, an infinity, or one no 32-bit integer holds is refused, never converted.

How a Check Works​

Every check dials a connection of its own, so each one measures its name resolved, its connection made, and its TLS handshake, and nothing stays open between checks. A Director whose environment names a proxy (HTTPS_PROXY, HTTP_PROXY) checks through it; the result then says so (service_check.http.proxied), and names no peer address, which would be the proxy's.

The check is up when an answer came, its status code is expected, and its body holds body_match. Otherwise it is down, and error.type says why:

error.typeWhen
connectionThe connection failed
timeoutNo answer within timeout
dnsThe URL's host does not resolve
certificateThe certificate does not verify
redirectMore than 10 redirects
statusA status code not expected
bodyThe body does not hold body_match

A check that could not be made — credentials that do not resolve — writes no result and is not counted in the state.

Results and State​

Every check writes one result, with event.dataset http_check and definition id 12150, to the metric table:

  • url.full (a credential-shaped query parameter masked), url.scheme, domain, port, path; http.request.method; http.response.status_code, mime_type, body.bytes.
  • destination.address, ip, port (the peer, without a proxy); network.transport, protocol.
  • tls.established, version, version_protocol, cipher; tls.server.x509.* (the service's own certificate, verified or not) and tls.server.hash.sha256 (its fingerprint).
  • service_check.http.rtt.dns, connect, tls_handshake, first_byte, content, total (the last request's parts it had), redirects, body.matched, body.truncated (the body went on past 10 MiB), proxied.
  • service_check.http.certificate.days_left (whole days, rounded down: an hour past its end is -1), certificate.chain.length, certificate.chain.days_left (the fewest any certificate of the chain has left), and certificate.chain.position, common_name, sha256 (which one that is: 0 is the service's own).

Every result carries the state the service is in, under state.*, and every service check writes the same fields. For the state's fields, how to alert on it, and the fields every record carries, see Results and State.

{
"@timestamp": "2026-09-28T12:00:00Z",
"ecs": {"version": "8.11.0"},
"event": {"module": "http_check", "dataset": "http_check", "kind": "metric",
"category": ["web", "network"], "type": ["info"], "outcome": "success", "duration": 120000000},
"observer": {"vendor": "VirtualMetric", "product": "HTTP Check", "name": "shop-https",
"hostname": "director01"},
"url": {"full": "https://shop.example.com/health", "scheme": "https", "domain": "shop.example.com",
"port": 443, "path": "/health"},
"http": {"request": {"method": "GET"},
"response": {"status_code": 200, "mime_type": "text/html", "body": {"bytes": 5120}}},
"destination": {"address": "shop.example.com", "ip": "192.0.2.80", "port": 443},
"network": {"transport": "tcp", "protocol": "http"},
"tls": {"established": true, "version": "1.3", "version_protocol": "tls", "cipher": "TLS_AES_128_GCM_SHA256",
"server": {"x509": {"not_before": "2026-07-29T12:00:00Z", "not_after": "2026-10-28T13:00:00Z",
"serial_number": "5EED", "alternative_names": ["shop.example.com"],
"subject": {"common_name": ["shop.example.com"], "distinguished_name": "CN=shop.example.com"},
"issuer": {"common_name": ["Example CA"], "distinguished_name": "CN=Example CA"}}}},
"service_check": {"kind": "http", "target": "https://shop.example.com/health", "status": "up",
"http": {"rtt": {"dns": {"us": 4000}, "connect": {"us": 10000}, "tls_handshake": {"us": 30000},
"first_byte": {"us": 50000}, "content": {"us": 20000}, "total": {"us": 120000}},
"redirects": 0, "body": {"matched": true}, "certificate": {"days_left": 30}}},
"state": {"id": "512300180-1a0e74bce20", "status": "up", "started_at": "2026-09-28T09:15:00Z",
"duration_ms": 9900000, "checks": 166, "up": 166, "down": 0, "changed": false}
}

Connection States​

The device's connection state follows the service checked, and the fleet list shows it:

StateWhen
ConnectedThe service is up
Connection errorIt does not answer, its name does not resolve, or it redirects endlessly
Certificate errorIts certificate does not verify
Authentication errorIt answered 401 or 407
ErrorIt answered wrong: another status code, or a body without the text
Configuration errorCredentials that do not resolve, or a configuration that does not validate

The message says what the check ran into (https://shop.example.com/health is down: connect: connection refused), in words that stay the same while the failure does, so the state moves only when the service's does. A redirect to another host that fails names that host: https://portal.example.com/ is down: the redirect to https://login.example.com failed: connect: connection refused.

Console​

In the console, go to Fleet Management > Devices > HTTP Check and click Add new device. The wizard's steps are:

  1. General settings, as on every device, with the device's pre-processing pipeline.
  2. Check settings: under Request, the URL, HTTP method (Optional), Expected status codes (Optional), Body match (Optional) (hidden for HEAD), and Follow redirects; for an https:// URL, the TLS settings; then Credentials: Username (Optional), Password (Optional), and the headers. With credentials over an http:// URL, the wizard warns that they are sent in cleartext.
  3. Advanced settings: Interval and Timeout.
  4. Review and create.

There is no Data collection step: an HTTP Check has no datasets.

Simulation​

The HTTP Check is not simulated. What it writes is what its check finds, with the state the service is in, which one generic sample cannot stand in for.

Examples​

Health Endpoint​

Checking a health endpoint every minute, requiring OK in its body. Every result carries the URL's certificate and the certificate of its chain that expires first...

devices:
- id: 512300180
name: shop-https
type: http_check
status: true
properties:
url: "https://shop.example.com/health"
body_match: "OK"
interval: 60

Private CA and Credentials​

Checking an internal API that a private CA signs, with basic authentication from a vault and an API key header, accepting 200 or 204...

devices:
- id: 512300181
name: billing-api
type: http_check
status: true
properties:
url: "https://billing.internal.example.com:8443/status"
method: GET
expected_status: [200, 204]
username: "svc-monitor"
password: "$secret{store=corp-vault,ref=billing/monitor}"
headers:
X-Api-Key: "${BILLING_API_KEY}"
tls:
ca_name: "certs/internal-ca.pem"
interval: 30