Prometheus Error Guide: 'HTTP response to HTTPS client' — Fix Scheme
Fix Prometheus 'HTTP response to HTTPS client' scrape errors: correct the scheme, TLS config, and relabeling so targets are scraped on the right protocol.
- #prometheus
- #monitoring
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
Prometheus records this on the target status page when it opens a TLS handshake against an endpoint that is actually serving plain HTTP:
Get "https://10.0.0.7:9100/metrics": http: server gave HTTP response to HTTPS client
It is the mirror image of the opposite mistake, where a plain-HTTP client hits a TLS port and gets binary garbage or a handshake error. In both cases the scrape scheme does not match what the target speaks. The target shows DOWN, up{} is 0, and no samples are ingested until the scheme is aligned.
Symptoms
- Target
DOWNwithhttp: server gave HTTP response to HTTPS client. up{job="..."} == 0only for jobs configured withscheme: httpsor atls_config.curl https://target/metricsfails the handshake whilecurl http://target/metricsreturns metrics.- The failure appeared right after enabling TLS, a ServiceMonitor change, or a relabel that set
__scheme__.
Common Root Causes
scheme: httpson a plain-HTTP exporter — most exporters (node_exporter, kube-state-metrics) serve HTTP by default.- Relabeling set
__scheme__to https via aprometheus.io/schemeannotation or a discovery default that doesn’t match reality. - ServiceMonitor
scheme: httpswithout the exporter’s web-config actually enabling TLS. - Port confusion — the HTTPS port points at a container listening only on HTTP.
- TLS terminated elsewhere — a sidecar/proxy expected to do TLS isn’t in the path, so Prometheus talks TLS directly to the plaintext app.
Diagnostic Workflow
Confirm what the endpoint actually speaks by probing both schemes from the Prometheus host:
curl -sS -o /dev/null -w 'http=%{http_code}\n' http://10.0.0.7:9100/metrics
curl -skS -o /dev/null -w 'https=%{http_code}\n' https://10.0.0.7:9100/metrics
If HTTP works and HTTPS errors, the target is plaintext and the scrape scheme is wrong. Inspect the derived scheme on the Service Discovery page, then check the scrape config:
scrape_configs:
- job_name: node
scheme: http # must match what the exporter serves
static_configs:
- targets: ["10.0.0.7:9100"]
For discovery-driven jobs, find any relabel rule setting the scheme:
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__ # this can force https incorrectly
For the Prometheus Operator, check the ServiceMonitor endpoint:
kubectl get servicemonitor my-app -o yaml | grep -A3 'scheme:'
Example Root Cause Analysis
A team enabled a cluster-wide default annotation prometheus.io/scheme: https intending to secure app traffic, but their node_exporter DaemonSet still served plaintext on :9100. Every node target flipped to DOWN with server gave HTTP response to HTTPS client.
Probing confirmed http=200 and the HTTPS probe failed the handshake. Because node_exporter was intentionally plaintext behind network policy, the correct fix was to scope the https default to app pods only and leave the node_exporter job on scheme: http. An alternative — actually enabling node_exporter’s --web.config.file TLS — was rejected as unnecessary for that trust boundary. Targets recovered immediately.
Prevention Best Practices
- Set
schemeexplicitly per job to match the exporter, rather than relying on a broad discovery default. - When enabling
scheme: https, enable TLS on the target in the same change (web-config or sidecar), never one without the other. - Scope scheme-setting annotations narrowly; a cluster-wide
prometheus.io/schemebreaks plaintext exporters. - After any TLS or ServiceMonitor change, verify the target on the Service Discovery page shows the intended
__scheme__. - Probe both schemes with
curlbefore flipping a job to https.
Quick Command Reference
# Which scheme does the target actually speak?
curl -sS -o /dev/null -w 'http=%{http_code}\n' http://TARGET:PORT/metrics
curl -skS -o /dev/null -w 'https=%{http_code}\n' https://TARGET:PORT/metrics
# Operator: inspect the ServiceMonitor scheme
kubectl get servicemonitor NAME -o yaml | grep -A3 'scheme:'
up == 0
Conclusion
server gave HTTP response to HTTPS client means Prometheus is speaking TLS to a plaintext endpoint. Probe both schemes to learn what the target actually serves, then align scheme (and any __scheme__ relabel or ServiceMonitor setting) to match — or enable TLS on the target if security requires it. Keep scheme defaults narrowly scoped so one annotation can’t break every plaintext exporter.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.