HTTP Check
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.
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
| Field | Required | Default | Description |
|---|---|---|---|
id | Y | - | Unique numeric identifier |
name | Y | - | Device name |
description | N | - | Optional description |
type | Y | - | Must be http_check |
tags | N | - | Optional tags |
status | N | true | Enable/disable the device |
Request
| Field | Required | Default | Description |
|---|---|---|---|
url | Y | - | 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 |
method | N | GET | GET, or HEAD, which reads no body |
expected_status | N | any 2xx | A status code, or a list of them, that mean up |
body_match | N | - | 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_redirects | N | true | Follows up to 10 redirects and reads the last answer; false reads the redirect itself |
Credentials
| Field | Required | Default | Description |
|---|---|---|---|
username, password | N | - | Sent as basic authentication. Plain text, ${ENV_VAR}, or $secret{...} |
headers | N | - | 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.
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
| Field | Required | Default | Description |
|---|---|---|---|
tls.status | N | the URL's | true for https://, false for http://. When given, it has to agree with the URL |
tls.insecure_skip_verify | N | false | true accepts any certificate, and still writes its expiry. Pin the CA instead where you can |
tls.ca_name | N | - | 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_name | N | - | The name the certificate is verified for, when it is not the URL's host |
tls.min_tls_version | N | tls1.2 | tls1.0 to tls1.3 |
tls.max_tls_version | N | - | 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
| Field | Required | Default | Description |
|---|---|---|---|
interval | N | 60 | Seconds between checks: a result every interval. At least 10 |
timeout | N | 10 | Seconds 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.type | When |
|---|---|
connection | The connection failed |
timeout | No answer within timeout |
dns | The URL's host does not resolve |
certificate | The certificate does not verify |
redirect | More than 10 redirects |
status | A status code not expected |
body | The 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) andtls.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), andcertificate.chain.position,common_name,sha256(which one that is:0is 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:
| State | When |
|---|---|
| Connected | The service is up |
| Connection error | It does not answer, its name does not resolve, or it redirects endlessly |
| Certificate error | Its certificate does not verify |
| Authentication error | It answered 401 or 407 |
| Error | It answered wrong: another status code, or a body without the text |
| Configuration error | Credentials 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
General settings , as on every device, with the device's pre-processing pipeline.Check settings : underRequest , theURL ,HTTP method (Optional) ,Expected status codes (Optional) ,Body match (Optional) (hidden forHEAD), andFollow redirects ; for anhttps://URL, theTLS settings ; thenCredentials :Username (Optional) ,Password (Optional) , and the headers. With credentials over anhttp://URL, the wizard warns that they are sent in cleartext.Advanced settings :Interval andTimeout .Review and create .
There is no
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 | |
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... | |