The port speaks TLS; the client spoke HTTP. Either the client hit the wrong port/scheme, or your nginx has ssl on a listener without an error-tolerant fallback. Both diagnosis and fix are one line each.
http://host:443, or a proxy/monitoring tool configured with http against your TLS listener. The nginx error is literally accurate: the client must use https:// on that port.
A 443 listener receiving both TLS and plain (some legacy clients, TCP checks). nginx detects the plain bytes against the ssl listener and emits the 400 explanation page.
curl -v https://host:443/ # if this works, the failing caller is using http:// — fix it there
# health checks, proxy_pass http://backend references, and upstream URLs against the TLS port must use https://
# listen 80; server with 301 to https + listen 443 ssl; — each port speaks exactly one protocol
# error_page 497 =301 https://$host$request_uri; # nginx code 497 = this exact mismatch, redirect it to HTTPS properly
497 is nginx's internal code for plain-HTTP-on-TLS-port: mapping it to a 301 gives old clients/bookmarks a self-healing path to the right scheme. This error is nginx protecting the protocol contract — a better description than a failure. The only question is which side is wrong: usually the caller.
The listener now requires TLS for everything. Any caller still using http:// against that port gets the 400. Audit the callers: health checks and internal proxies are the usual stragglers.
nginx's internal status for exactly this mismatch (plain bytes on an ssl listener). It's why error_page 497 works as a targeted fix: it fires only for this case, never for real 400s.
Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.
Browse the template store →One-time. Yours to modify. Instant download from the NinjaOps template store.