Skip to content
ecdsa.com
curl (OpenSSL backend)curl

Error message

curl: (60) SSL: no alternative certificate subject name matches target hostname 'api.example.com'

Also printed as

  • curl: (60) SSL: no alternative certificate subject name matches target host name 'api.example.com'

curl 8.x prints "target hostname"; curl 7.x printed "target host name". The quoted host is whatever the URL contained. Very old curl versions (before 7.62.0) used exit code 51 for this check.

curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, hostname check in lib/vtls/openssl.c

What it means

The certificate chain is trusted, but none of the DNS names (or IP addresses) in the certificate's Subject Alternative Name extension match the host in the URL. curl compares the URL's host with the SAN entries only; the subject's Common Name is ignored when a SAN extension is present. The quoted name at the end is the host curl was asked to reach.

Why it happens

How to fix it

  1. 1.

    Compare the SAN list with the URL

    Print the subjectAltName extension of the served certificate. The fix is either a certificate that lists the name or a URL that uses one of the listed names.

    bash
    # Names the served certificate actually covers
    echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \
      | openssl x509 -noout -subject -ext subjectAltName
  2. 2.

    Reissue the certificate with every name in use

    Request all hostnames (and IP addresses, if clients connect by IP) as SAN entries. Putting the name only into the Common Name does not work with any current client.

    bash
    # ACME: list every name the certificate must cover
    sudo certbot certonly --nginx -d example.com -d www.example.com -d api.example.com
    
    # Private CA: put all names into subjectAltName (CN is ignored for matching)
    openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \
      -addext "subjectAltName=DNS:api.example.com,DNS:www.example.com,IP:10.0.0.5"
  3. 3.

    Keep the name, change only the address

    When you must reach a specific address (a load balancer node, a tunnel, a staging IP), --resolve or --connect-to keeps the URL's host, so SNI and the hostname check still use the certificate's name.

    bash
    # Keep the certificate's name in the URL and steer the connection to another address
    curl --resolve api.example.com:443:10.0.0.5 https://api.example.com/
    curl --connect-to api.example.com:443:lb-internal.example.net:443 https://api.example.com/
  4. 4.

    Server owners: check SNI routing

    If the certificate differs between requests with and without SNI, add a server block (or ingress rule) for the name and make sure the default certificate is not what clients get for real hostnames.

    bash
    # Compare what the server returns with and without SNI
    openssl s_client -connect 10.0.0.5:443 -servername api.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject
    openssl s_client -connect 10.0.0.5:443 -noservername </dev/null 2>/dev/null | openssl x509 -noout -subject

Related errors

Browse the full signature error database