Problem:

During migration to Zabbix 7.4, hundreds of HTTPS health checks failed because the HTTP Host header differed from the SNI hostname used for the TLS handshake.

In this environment, monitoring items connect to a load-balancer VIP using a custom Host header to reach specific virtual sites. However, the target servers detected the discrepancy between the SNI and the Host header during the initial “greeting” phase (ClientHello). This caused an immediate connection reset (Connection reset by peer), preventing any HTTP exchange.

The native Zabbix HTTP Agent created a deadlock: its GUI does not allow for separate control over the SNI hostname, DNS target, and Host header. Since security policies forbade disabling certificate validation, the built-in approach was blocked, necessitating a custom architectural solution to handle complex HEAD/GET requests at scale.

Process:

Step 1: Verify symptom reproducibility and capture failure mode

Reproduced the failure using curl from a Linux host that mirrors the Zabbix execution environment: issuing curl -I against the VIP while sending a differing Host header caused an immediate TLS reset in the ClientHello phase. TLS logs and curl/OpenSSL error text confirmed the server closed the connection before any HTTP request was transmitted. This confirmed the problem was SNI/Host mismatch at TLS negotiation, not application‑level authentication or content handling.

Step 2: Inspect Zabbix HTTP Agent behavior and implementation constraints

Reviewed Zabbix 7.4 HTTP Agent item behavior and found SNI is derived from the URL hostname and the GUI does not expose curl options such as –resolve or –connect-to. Confirmed the HTTP Agent uses libcurl internally on server/proxy processes; switching to a Windows proxy would not change that behavior. This established there was no simple configuration toggle in Zabbix to separate SNI, DNS target, and Host header.

Step 3: Evaluate alternative Zabbix mechanisms

Compared available options: Agent UserParameters, External Checks, and Agent2 extensibility. Agent2 offered certificate metadata APIs but not full HTTP checks with content evaluation. External Checks and UserParameters allow arbitrary shell commands (including curl –resolve). External Checks run on server/proxy without editing agent configs; UserParameters require agent config changes per host but can run locally. This analysis identified viable execution surfaces to run a customized curl wrapper that controls SNI and resolution.

Step 4: Design for required features and constraints

Captured functional requirements: support HEAD and GET per monitored page, capture HTTP status and response time, capture and parse body for JSON/XML checks, pass authentication securely, and scale via low‑level discovery (LLD). Identified operational constraints: agent/external check timeouts, maximum return payload size, and the need to avoid manual per‑check config edits at scale. These constraints drove the architecture toward a centralized script executed by proxies or external checks with LLD-driven item generation and host/macros for credentials.

Step 5: Prototype an execution wrapper and LLD integration

Built a small shell wrapper executed as an External Check on Zabbix proxy hosts. The script was written in Pure Bash to eliminate external dependencies (like Python) in compliance with strict bank policies. The wrapper calls curl with –resolve to bind an SNI/host to a specific IP, accepts parameters (SNI, target IP, path, auth macro), supports a HEAD or GET mode, enforces –max-time, and returns a compact JSON payload containing http_code, time_total, cert_info, and a trimmed body field when requested. A discovery script outputs standard Zabbix LLD JSON that enumerates pages to monitor; item prototypes call the wrapper with LLD macros. Preprocessing (JSONPath) extracts discrete items for triggers and graphs.

Step 6: Address security, scalability and agent limits

To avoid plaintext credentials in config files, credentials are stored as host‑level macros and referenced in item parameters or passed to the proxy wrapper through secure host macros. To ensure enterprise-grade security, the implementation was hardened to pass credentials through environment variables and temporary configuration files, effectively preventing sensitive data exposure in the process list (ps aux). Response size is limited on the wrapper (body trimmed and optional), and heavy body parsing is performed only when required. For scale, multiple proxy hosts were used to distribute checks and Zabbix timeouts were tuned (proxy and external check timeouts) to accommodate concurrent execution. This design eliminated per-item agent config edits and supported automatic item creation via LLD.

Step 7: Validate and transition to the implemented fix

Smoke tests ran the External Check wrapper against representative pages: HEAD checks returned status codes and timings; GET checks returned small JSON payloads that were successfully preprocessed into separate items and used by existing trigger prototypes. Response behavior matched the previous monitoring solution where SNI/Host separation was required. With these validations complete, the technical architecture and production-ready scripts were delivered to the client’s engineering team for internal implementation.

Solution:

The final implementation used Zabbix External Checks executed on Linux proxy hosts. A compact wrapper script invokes curl with –resolve to control SNI and DNS target while sending a custom Host header, and returns a compact JSON object. Zabbix LLD produces item and trigger prototypes that call the External Check with LLD macros; JSON preprocessing extracts status, response time, certificate metadata, and body snippets. Credentials are provided by host macros and the wrapper trims/stores only required data. Architecturally this works because External Checks run outside the HTTP Agent libcurl path, permitting explicit control of the transport (curl flags) while integrating with Zabbix item/trigger lifecycle and preprocessing.

Conclusion:

The proposed architecture provided a reliable path for checks that previously failed at TLS negotiation. The solution was formally accepted by the client as the foundational framework for their internal implementation. The solution removed manual agent config edits, supported discovery-driven scaling, and confined authentication data to secure host macros, improving operational manageability and restoring monitoring coverage for virtual‑hosted HTTPS services behind load balancers.