Servers and proxies
Nginx: no "ssl_certificate" is defined in server listening on SSL port
no "ssl_certificate" is defined in server listening on SSL port while SSL handshaking, client: 203.0.113.10, server: 0.0.0.0:443This error means a TLS client reached a server block on an SSL port that has no ssl_certificate, so Nginx had nothing to present and aborted the handshake. Most often that block is the default server for port 443, which receives connections by IP address, without SNI, or for hostnames you do not serve.
Quick fix
The port 443 server block without ssl_certificate needs a certificate or ssl_reject_handshake on;.
List every server block on port 443 and see which ones lack a certificate:
sudo nginx -T 2>/dev/null | grep -nE "server_name|listen .*443|ssl_certificate |default_server"
Then either give that block a certificate, or make your catch-all reject TLS handshakes explicitly (Nginx 1.19.4 or later):
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_reject_handshake on;
}
Run sudo nginx -t && sudo systemctl reload nginx. The SSL checker shows which certificate each hostname now receives.
Causes
1. A catch-all or default server without a certificate
When any server uses listen 443 ssl, every server on that address and port handles TLS. A catch-all such as server_name _; copied from a port 80 template, or the distribution's default site, often has no certificate.
- Confirm: the error's
server:field is0.0.0.0:443or[::]:443, andnginx -Tshows a block on that port withoutssl_certificate. - Fix: add
ssl_reject_handshake on;to that block, or remove it if you do not need it.
2. Clients that do not send SNI, or connect by IP
Scanners, health checks and old clients connect without SNI. Nginx cannot pick the named server and falls back to the default.
- Confirm:
openssl s_client -connect 203.0.113.10:443 -noservernamefails, while-servername example.comworks. - Fix: mark the real site as
default_serverif it should answer IP connections, or keep the rejecting catch-all. Make health checks send the hostname.
3. Certificate directives in the wrong place
ssl_certificate belongs in http or server context. It is not inherited from another server block, and a location block cannot hold it.
- Confirm: the certificate is configured only in a different server block for the same name, or in an include file that is not loaded (
nginx -Tdoes not show it). - Fix: move the directives into the server block that has the matching
server_name, or include the snippet there.
4. Duplicate server blocks for the same name
Tools such as Certbot's Nginx plugin edit one block; if you have two blocks with the same server_name on 443, Nginx uses the first and warns about a conflicting name.
- Confirm:
nginx -tprintsconflicting server name "example.com" on 0.0.0.0:443, ignored. - Fix: merge the blocks so one block per name and port holds the certificate.
5. Certificate loaded from variables
Since Nginx 1.15.9 ssl_certificate can contain variables. If a variable resolves to an empty value or missing file, the handshake fails for those names.
- Fix: check the map that sets the variable and provide a default.
Fixes by environment
On every platform, give the default server on port 443 a certificate or ssl_reject_handshake on;.
Debian / Ubuntu packages: the default site in /etc/nginx/sites-enabled/ listens on port 80 only by default, but edited copies often add 443. Disable it or give it ssl_reject_handshake on;.
Docker / Nginx Proxy Manager: the generated default server may have no certificate. Configure a default certificate or a rejecting default in the proxy settings.
Kubernetes ingress-nginx: the controller serves its own fake default certificate for unknown hosts, so this message rarely appears; a name mismatch for unknown hosts is expected there.
Older Nginx (before 1.19.4): ssl_reject_handshake is not available; give the catch-all a self-signed certificate and return 444 to close connections.
Don't do this
- Serve your real certificate on the catch-all for every unknown name. Visitors reaching the wrong name get a name mismatch, and you advertise your domains to IP scanners.
- Remove
sslfromlistento make the error disappear. The port would then speak plain HTTP to TLS clients and every HTTPS visitor would fail. - Ignore the log entirely. Usually harmless, but the same message also appears when a real site loses its certificate during a config change.
FAQ
Why does my site work while the log keeps showing this error?
Your named server has a certificate, but scanners and bots connect by IP or with unknown hostnames and land on the default server, which has none. The error is noise for those clients but harmless for your visitors. Add a catch-all with ssl_reject_handshake on; to stop it.
Can I put ssl_certificate in the http block?
Yes. Directives in the http block are inherited by every server that does not set its own. This gives every SSL server a fallback certificate, but clients that reach the wrong server will see a name mismatch instead of a handshake failure.
Is this the same as the "no ssl_certificate is defined for the listen ... ssl directive" error?
They have the same root cause. The configuration-time variant is reported by nginx -t when a server block with listen ... ssl has no certificate; the handshake-time variant appears in error.log when a client reaches such a block.