Comparing check_http, check_httpv2, and check_cert in Checkmk

Comparing check_http, check_httpv2, and check_cert in Checkmk

This article compares check_http, check_httpv2, and check_cert in Checkmk, with migration guidance and troubleshooting tips

LAST TESTED ON CHECKMK 2.4.0p10

 

Table of Contents

The roadmap is still under development and will be shared once priorities and timelines are finalized. Updates will follow as soon as concrete milestones are available.

 

Introduction

Why we had to create check_httpv2

The classic check_http plugin is one of the oldest and most widely used active checks in monitoring systems, written by Ethan Galstad dating back more than 25 years. Over time, it accumulated many extensions that introduced inconsistencies, unpredictable behavior, and even violations of standards. 


check_httpv2 is not a rewrite but a complete new implementation

To modernize this essential functionality, Checkmk introduced check_httpv2, a complete re-implementation written in Rust. Unlike a rewrite, this plugin was designed with a clean slate to provide a more intuitive interface and improved features. Migration is not always seamless, but check_httpv2 offers clearer, stricter defaults and long-term maintainability.

In addition, Checkmk now provides check_cert for focused on Secure Sockets Layer / Transport Layer Security (SSL/TLS) certificate validation.

 

Two ways of monitoring web endpoints

  • Use check_cert
    If your primary goal is detailed certificate validation (expiry, issuer, subject fields, self-signed, algorithms, etc.)

  • Use check_httpv2
    If you're already doing HTTP monitoring and just want to include certificate expiration as part of the check.

 

Key Differences: check_http vs. check_httpv2

Feature

check_http (v2.4.0)

check_httpv2

Language

C

Rust

Usage style

Many single-letter flags (-H, -I, -u, etc.)

Long-form options (--url, --timeout, etc.)

Auth options

Basic Auth only (-a)

Basic & Token Auth (headers, pw store)

Certificate checks

With -C, but less flexible

Granular with --certificate-levels, TLS versioning

Header matching

Simple string/regex search (-d, -s, -r, -R)

Powerful header regex and key:value parsing

Body matching

String/regex options, basic

Multiple --body-string, --body-regex, inversion

Request customization

Supports POST data with -P, headers with -k

Supports full body content with --body, --method

Proxy support

Rudimentary, via -I, -j CONNECT

Native via --proxy-url, --proxy-user, etc.

TLS control

Supports specific versions (-S)

Fine-grained with --tls-version, --min-tls-version

Performance data

With -w, -c, perf output optional

--response-time-levels, better performance flags

Output verbosity/debugging

-v, but limited info

Multiple levels -v, -vvv, RUST_LOG support

URL definition

Via -H, -I, -u

Unified --url parameter

IPv6 support

Via -4, -6

Via --force-ip-version

 

Key Differences: check_httpv2 vs. check_cert

Feature

check_httpv2

check_cert

Certificate expiry checking

Yes (--certificate-levels WARN,CRIT)

 Yes (--not-after WARN CRIT)

Detailed cert field checks

 No  

 Yes (CN, SAN, O, OU, Issuer fields, algorithms)

Self-signed certificate support

Limited (not recommended)

 Yes (--allow-self-signed)

Certificate validity length limit

 Not available

 Yes (--max-validity)

Signature / Public key checks

No

 Yes (--signature-algorithm, --pubkey-*)

Response time checks

Yes (--response-time-levels)

 Yes (--response-time WARN CRIT)

TLS version selection

Yes (--tls-version, --min-tls-version)

No direct control

Works without HTTP

 No (HTTPS only, via --url)

 Yes (direct TLS, no web server required)

 

Please read the following if you want to know more about Rust reqwest.

Current feature gaps (and why these exist)

Certificate handling

In the legacy check_http, HTTPS checks did not validate certificate validity by default.
By contrast, check_httpv2 always validates certificates.

You can adjust this behavior with:

OMD[mysite]:~/lib/nagios/plugins$ ./check_httpv2 --v2-checks-certificates skip|keep|disable

 

Available options:

  • skip: skips the certificate checks.

  • keep: retain the stricter default (recommended).

  • disable: ignore certificate checks entirely.

 

For certificate-only checks, the difference is similar:

  • check_http validated only the remaining validity period.

  • check_httpv2 validates the entire certificate chain and details.

Use --cant-ignore-certificate-validation during migration to decide whether to adopt this stricter validation or skip the affected rules.

 

Recommended Approach

If you migrate to the stricter defaults, you can include both certificate validity and remaining lifetime checks in a single URL check. This reduces the number of active checks per host.

 

Host Address vs. Host Name

Another important change:

  • check_http used the host address as the default connection target, including in the HTTP request header.

  • check_httpv2 uses the host name instead.

This is automatically mapped during migration to minimize issues.
However, if you explicitly configured the $HOSTADDRESS$ macro, it will not be replaced. In that case, checks may fail until updated manually.

 

TLS/SSL Version Incompatibilities

check_httpv2 supports only TLS 1.2 and TLS 1.3.

If you have rules configured for older TLS/SSL versions, they will no longer work with the new check.

To handle such cases during migration, use --ssl-incompatible negotiate

This changes the migrated rule to use version negotiation instead of forcing an unsupported TLS version.

If you still need to monitor services that rely on outdated protocols (e.g., TLS 1.0 or 1.1), refer to the How to monitor servers with broken TLS in Checkmk 2.3 on handling the OpenSSL 3.x update, which introduced incompatibilities with these older versions.

Headers

In check_http, request and response headers could be defined in a free-form way.
In contrast, check_httpv2 requires headers to follow the strict Header: value format.

Rules that don’t comply with this scheme need manual intervention during migration.

You can handle them with:

  • --add-headers-incompatible skip 
    Skip migrating the rule.

  • --expect-response-header ignore 
    Force migration but remove the invalid header definition.

After migration, review and adjust these rules as needed to restore the intended behavior.

 

Status codes

In the legacy check_http, it was possible to specify arbitrary status codes, including nonstandard values like 320 (or 737...) or even strings (see Werk #17738).

In some cases, if the specified string appeared anywhere in the response headers, the check would incorrectly succeed.

check_httpv2 enforces stricter validation and only accepts valid three-digit HTTP status codes.

During migration, you can use --only-status-codes-allowed ignore

This removes invalid codes from the rule and allows the migration to proceed.

After migration, review the affected rules carefully to confirm that the new behavior matches your expectations.

 

Redirects

In the legacy check_http, redirects were not followed when evaluating other aspects of the response (e.g., searching for strings in the body).

By contrast, check_httpv2 always follows redirects first, and then performs the checks.

  • To acknowledge and accept this new behavior during migration, use --v1-skips-redirect-response acknowledge

  • Redirect handling can later be fine-tuned when testing and adjusting rules.

 

Example: Following Redirects

OMD[mysite]:~/lib/nagios/plugins$ ./check_httpv2 --url https://www.checkmk.com URL to test: https://www.checkmk.com/ Followed redirect to: https://checkmk.com/ Method: GET Version: HTTP/2.0 Status: 200 OK Response time: 0.27 seconds Page size: 155146 Bytes User agent: checkmk-active-httpv2/2.4.0

 

Using the --server Option

You can also check availability directly against a specific backend server instead of the URL:

OMD[mysite]:~/lib/nagios/plugins$ ./check_httpv2 --url https://example.com --server 192.0.2.73


This approach bypasses the URL resolution and targets the forwarding destination (the actual server IP).

In practice, this makes it possible to define rules with multiple endpoints, allowing you to monitor both the public-facing URL and each server behind a load balancer.

In Checkmk, this configuration corresponds to “Connect to physical host”.


HTTP methods

check_httpv2 no longer supports the following methods: OPTIONS, TRACE, CONNECT, CONNECT_POST, PROPFIND.

  • If your old configuration relies on these, use --method-unavailable to handle the migration:

    • Switches to GET if no POST data is present.

    • Switches to POST if POST data is present.


Unlike check_http, which allowed POST data to be used with non-POST methods, check_httpv2 enforces stricter rules and does not permit this configuration.

If such a rule is encountered, you can:

  • Use --cant-post-data post to force the request into a POST method.

  • Use --cant-post-data prefermethod to preserve the method but drop the POST data.

 

Proxies

Proxy settings cannot be migrated automatically due to differences in data structures and dependencies. Any rules that use proxies will be skipped during migration and must be recreated manually.

Recommendation

Configure proxies in the global settings first, then re-create the necessary rules to ensure consistent behavior.

 

check_cert: A dedicated certificate validation plugin

The check_cert plugin is a new addition to Checkmk that focuses specifically on SSL/TLS certificate validation. In many cases, it is preferable to use check_cert instead of check_httpv2 when the goal is in-depth certificate testing.

 

Key Capabilities

  • Detailed field checks (CN, SAN, Issuer, algorithms, etc.)

  • Support for self-signed certificates

  • Validation of maximum certificate lifetime

 

Self-Signed Certificates (--allow-self-signed)

The --allow-self-signed option extends support for environments where self-signed certificates are required, even when they appear within the certificate chain.

  • Enabling this option suppresses OpenSSL error 18 (X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT), so the service does not warn about self-signed certificates.

  • Other validation errors will still be reported.

 

This option does not bypass full chain validation. For example, you may still encounter OpenSSL error 20 (X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) if the chain cannot be completed to a trusted CA.

 

Protocol Support

Currently, check_cert supports direct SSL/TLS connections only. Monitoring services that rely on STARTTLS is not yet possible.

 

Self-testing

If you’re unsure how check_httpv2 behaves, or want to experiment with specific configurations, we recommend using badssl.com.

This site provides a wide range of test URLs that simulate different certificate and TLS scenarios, making it ideal for safe self-testing and troubleshooting.

 

 

Future Plans

Version 2.4.0

  • Support for STARTTLS certificates will be added to both check_cert and check_httpv2.

Version 2.5.0

  • Improvements are planned to make proxy configuration easier in check_httpv2.

    • Currently, the Checkmk UI only accepts proxies in full URI format (e.g., https://username:password@proxyserver.tld:3128).

    • This setup is neither flexible nor user-friendly, and work is underway to allow more granular proxy configuration.

  • Efforts are ongoing to enable certificate validity checks for websites behind a proxy.

    • In contrast, the legacy check_http plugin only checked the validity period, not the actual correctness or ownership of the certificate.

    • This functionality has not yet been implemented in check_httpv2 due to technical limitations, but it remains a priority.

 

Troubleshooting and known Issues

This section outlines common issues encountered when using check_cert and check_httpv2, along with explanations and possible workarounds.

Issues with check_cert

Verification: Unable to Get Local Issuer Certificate

This error indicates that check_cert cannot validate the certificate chain up to a trusted root CA.

Possible causes:

  • The server presents an incomplete certificate chain (missing intermediates).

  • The Checkmk server does not have the necessary CA certificate in its trust store.

  • check_cert is not configured to use the correct CA.


Why it works with check_http

Unlike check_cert, the legacy check_http plugin does not enforce full certificate chain validation.

It only checks:

  • Whether a certificate is presented.

  • Whether the certificate’s expiration date is within the configured limits (-C).

 

Example (works with check_http):

OMD[mysite]:~/lib/nagios/plugins$ ./check_http -C 7,14 -H 10.200.3.20 -p 6443 OK - Certificate 'kube-apiserver' will expire on Fri Apr 24 22:07:45 2026 +0000

 

Example (fails with check_cert):

OMD[mysite]:~/lib/nagios/plugins$ ./check_cert --url 10.200.3.20 -p 6443 Verification: unable to get local issuer certificate (!) Subject CN: kube-apiserver Issuer CN: kubernetes Server certificate validity: 323 day(s)

 

Solution:
Export the missing CA certificate from the Kubernetes API server and add it to your Checkmk site:

# On K8s host root@node1:~# cat /etc/kubernetes/pki/ca.crt > $OMD_ROOT/certs/k8.crt # On Checkmk host OMD[mysite]:~/lib/nagios/plugins$ ./check_cert --url 10.200.3.20 -p 6443 --ca-store ~/certs/k8.crt Verification: OK, Subject CN: kube-apiserver

 


 

Not Possible to Monitor Postgres with STARTTLS

Currently, check_cert only supports direct SSL/TLS connections. Monitoring Postgres with STARTTLS is not yet possible.


Symptoms:

  • The handshake fails with unexpected EOF.

  • openssl s_client against the port also shows no peer certificate available.

 

Example: Fails with check_cert:

OMD[mysite]:~/lib/nagios/plugins$ ./check_cert --url <IP> --port 15321 -vvv --allow-self-signed INFO: start check-cert INFO: contact host... the handshake failed: unexpected EOF (!!)

 

Example: Confirmed with OpenSSL:

OMD[mysite]:~$ openssl s_client -connect <IP>:15321 CONNECTED(00000003) error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading no peer certificate available

 

Workaround:

Use openssl s_client -starttls postgres manually.

 

Example: Works with STARTTLS (manual test):

OMD[mysite]:~$ openssl s_client -connect <IP>:5444 -starttls postgres CONNECTED(00000003) depth=2 C = DE, O = <Org>, OU = <Unit>, CN = <Root CA> verify return:1 depth=1 C = DE, O = <Org>, OU = <Unit>, CN = <Intermediate CA> verify return:1

 

Planned Improvement

STARTTLS support is planned for a future release.

 


Issues with check_httpv2

Certificate Monitoring Behind a Proxy

Currently, check_httpv2 does not display certificate information when used with a proxy.

  • check_http supported certificate checks via -j CONNECT with a proxy.

  • check_httpv2 does not currently display certificate details when used with a proxy.

 

Example: works with check_http:

OMD[mysite]:~/lib/nagios/plugins$ ./check_http -C 14,7 --ssl -j CONNECT -b proxyuser:hellothere -p 3128 -I <IP> -H <HOSTNAME> OK - Certificate '*.<HOSTNAME>' will expire on Sat Feb 7 23:59:59 2026 +0000.

 

Example: with check_httpv2:

OMD[mysite]:~/lib/nagios/plugins$ ./check_httpv2 --url https://<HOSTNAME> --method GET \ --proxy-url http://proxyuser:hellothere@<IP>:3128 --certificate-levels 40,20

 

Output (no certificate info):

Version: HTTP/1.1, Status: 200 OK | response_time=0.405s;;;0;10 ... URL to test: https://<HOSTNAME>/ Followed redirect to: https://<HOSTNAME>/ui/ Method: GET Status: 200 OK