nginx/nginx · error
400 The plain HTTP request was sent to HTTPS port
Error message
400 The plain HTTP request was sent to HTTPS port
What it means
This is nginx's built-in error page for pseudo-status 497 (NGX_HTTP_TO_HTTPS, defined in src/http/ngx_http_request.h), served to the client with status 400. When a listener has 'ssl' enabled, nginx expects a TLS handshake; if the first bytes parse as a plain HTTP request line instead, nginx logs "client sent plain HTTP request to HTTPS port" (src/http/ngx_http_request.c:2142) and sends this page from the ngx_http_error_pages[] table in ngx_http_special_response.c. It means the client used the wrong scheme for that port.
Source
Thrown at src/http/ngx_http_special_response.c:282
"<head><title>400 The SSL certificate error</title></head>" CRLF "<body>" CRLF "<center><h1>400 Bad Request</h1></center>" CRLF "<center>The SSL certificate error</center>" CRLF ; static char ngx_http_error_496_page[] = "<html>" CRLF "<head><title>400 No required SSL certificate was sent</title></head>" CRLF "<body>" CRLF "<center><h1>400 Bad Request</h1></center>" CRLF "<center>No required SSL certificate was sent</center>" CRLF ; static char ngx_http_error_497_page[] = "<html>" CRLF "<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>" CRLF "<body>" CRLF "<center><h1>400 Bad Request</h1></center>" CRLF "<center>The plain HTTP request was sent to HTTPS port</center>" CRLF ; static char ngx_http_error_500_page[] = "<html>" CRLF "<head><title>500 Internal Server Error</title></head>" CRLF "<body>" CRLF "<center><h1>500 Internal Server Error</h1></center>" CRLF ; static char ngx_http_error_501_page[] =
View on GitHub (pinned to 3f6f7824d4)
Solutions
- Change the client to use https:// against the TLS port (or http:// against a plain port).
- If you want an automatic upgrade, add 'error_page 497 =301 https://$host$request_uri;' to the ssl server block.
- Split listeners: one 'listen 80;' server that redirects and one 'listen 443 ssl;' server for TLS traffic.
- For proxy hops, fix the upstream scheme: 'proxy_pass https://backend;' or set the load balancer backend protocol to HTTPS/TLS.
Example fix
// before
server {
listen 443 ssl;
server_name example.com;
}
// client: curl http://example.com:443/ -> 400 The plain HTTP request was sent to HTTPS port
// after
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
error_page 497 =301 https://$host$request_uri;
} Defensive patterns
Strategy: validation
Validate before calling
# before connecting, verify the scheme/port pairing actually served scheme=443_tls_only curl -sI "http://$host:$port/" | head -n1 # if this prints '400 ... HTTPS port', use https curl -sI "https://$host:$port/" | head -n1 # this must succeed
Try / catch
try:
r = requests.get(f"https://{host}:{port}/", timeout=10)
except requests.exceptions.SSLError:
# port is NOT speaking TLS even though we assumed https
raise Prevention
- Keep a single source of truth mapping host:port -> scheme; never guess.
- Configure health checks with the exact scheme of the listener.
- Add 'error_page 497 =301 https://$host$request_uri;' so wrong-scheme requests self-heal.
- In CI, assert that https:// probes succeed on every TLS endpoint before shipping config.
When it happens
Trigger: Running 'curl http://example.com:443/' against a 'listen 443 ssl;' server; a health checker or uptime monitor configured with http:// against the TLS port; a load balancer whose backend protocol is HTTP while the target expects TLS; an internal proxy_pass that omits 'https://' so nginx speaks plain HTTP to a TLS upstream.
Common situations: Container port remapping that maps container 443 to host 8080 and clients then try http://host:8080; AWS ELB/ALB target-group protocol mismatch; scripts where the scheme is built from config and defaults to http; migration from port 80 to 443 without updating monitoring probes.
Related errors
AI-assisted analysis of nginx/nginx@3f6f7824d4 (2026-08-22).
Data as JSON: /api/errors/e99c4e2a8a97f1ab.
Report an issue: GitHub.