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
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 | Long-form options |
Auth options | Basic Auth only | Basic & Token Auth (headers, pw store) |
Certificate checks | With | Granular with |
Header matching | Simple string/regex search | Powerful header regex and key:value parsing |
Body matching | String/regex options, basic | Multiple |
Request customization | Supports POST data with | Supports full body content with |
Proxy support | Rudimentary, via | Native via |
TLS control | Supports specific versions | Fine-grained with |
Performance data | With |
|
Output verbosity/debugging |
| Multiple levels |
URL definition | Via | Unified |
IPv6 support | Via | Via |
Key Differences: check_httpv2 vs. check_cert
Feature | check_httpv2 | check_cert |
Certificate expiry checking | Yes ( | Yes |
Detailed cert field checks | No | Yes (CN, SAN, O, OU, Issuer fields, algorithms) |
Self-signed certificate support | Limited (not recommended) | Yes |
Certificate validity length limit | Not available | Yes |
Signature / Public key checks | No | Yes |
Response time checks | Yes | Yes ( |
TLS version selection | Yes | No direct control |
Works without HTTP | No (HTTPS only, via | 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_httpvalidated only the remaining validity period.check_httpv2validates 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_httpused the host address as the default connection target, including in the HTTP request header.check_httpv2uses 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 acknowledgeRedirect 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-unavailableto 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 postto force the request into a POST method.Use
--cant-post-data prefermethodto 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_certandcheck_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_httpplugin only checked the validity period, not the actual correctness or ownership of the certificate.This functionality has not yet been implemented in
check_httpv2due 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_certis 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_clientagainst the port also showsno 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_httpsupported certificate checks via-j CONNECTwith a proxy.check_httpv2does 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