Skip to content
ecdsa.com
nginxOther tools

Error message

400 No required SSL certificate was sent

Also printed as

  • client sent no required SSL certificate while reading client request headers

The page title is "400 No required SSL certificate was sent"; with a certificate that fails verification nginx shows "400 The SSL certificate error" instead. The log line is written at info level, so it is invisible with the default error_log level.

nginx — ssl_verify_client on, request without a client certificate

What it means

nginx is configured for mutual TLS (ssl_verify_client on) and the request arrived over a TLS connection on which the client presented no certificate. Instead of failing the handshake, nginx finishes it and answers every request with this HTTP 400 page, logging "client sent no required SSL certificate" at info level. The fix is on the client: it has to present a certificate issued by the CA in ssl_client_certificate.

Why it happens

How to fix it

  1. 1.

    Present the client certificate

    Pass certificate and key to the client; for browsers and Windows/macOS key stores, package them as PKCS#12 and import the file.

    bash
    curl --cert client.pem --key client.key https://mtls.example.com/
    # Browsers: import the client certificate with its key as PKCS#12
    openssl pkcs12 -export -in client.pem -inkey client.key -out client.p12
  2. 2.

    Proxying to an mTLS service: configure the upstream certificate

    When nginx itself is the client of the mTLS service, proxy_ssl_certificate and proxy_ssl_certificate_key provide the certificate on the upstream connection.

    text
    # nginx proxying to an mTLS upstream: present the client certificate on the upstream connection
    location / {
        proxy_pass https://mtls.example.com;
        proxy_ssl_certificate     /etc/nginx/tls/client.pem;
        proxy_ssl_certificate_key /etc/nginx/tls/client.key;
        proxy_ssl_server_name     on;
    }
  3. 3.

    Require certificates only where needed

    ssl_verify_client optional plus a check of $ssl_client_verify per location keeps health checks and public paths reachable without a certificate.

    text
    # Require the certificate only where needed
    ssl_verify_client optional;
    location /api/ {
        if ($ssl_client_verify != SUCCESS) { return 403; }
    }

Related errors

Browse the full signature error database