When setting up SSL with Nginx, one of the most frustrating errors you might encounter is:
no "ssl_certificate" is defined in server listening on SSL port while SSL handshaking
This typically occurs when Nginx can't locate or access your SSL certificate files, even when they appear to be in the correct location. Let's dive into troubleshooting this issue.
First, verify the certificate files actually exist and have proper permissions:
sudo ls -la /etc/letsencrypt/live/pumaportal.com/
sudo stat /etc/letsencrypt/live/pumaportal.com/fullchain.pem
sudo stat /etc/letsencrypt/live/pumaportal.com/privkey.pem
Check file ownership and permissions (should be readable by Nginx user):
sudo chown -R root:root /etc/letsencrypt/live/
sudo chmod -R 755 /etc/letsencrypt/live/
Your configuration looks correct at first glance, but let's examine potential issues:
server {
listen 443 ssl;
server_name pumaportal.com www.pumaportal.com;
# Critical SSL directives
ssl_certificate /etc/letsencrypt/live/pumaportal.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pumaportal.com/privkey.pem;
# Recommended SSL settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256...';
# Other configuration...
}
Let's Encrypt uses symbolic links in the live directory. Verify they point correctly:
ls -l /etc/letsencrypt/live/pumaportal.com/
readlink -f /etc/letsencrypt/live/pumaportal.com/fullchain.pem
If everything looks correct but still fails, try these steps:
# Test Nginx configuration
sudo nginx -t
# Check error logs in real-time
sudo tail -f /var/log/nginx/error.log
# Verify SSL handshake
openssl s_client -connect pumaportal.com:443 -servername pumaportal.com
Here's a verified working configuration for reference:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256...';
ssl_prefer_server_ciphers on;
# HSTS (optional)
add_header Strict-Transport-Security "max-age=63072000" always;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
When you see the error message "no 'ssl_certificate' is defined in server listening on SSL port while SSL handshaking", it means Nginx cannot locate or properly access your SSL certificate files despite your configuration appearing correct. Let's break down the verification steps:
First, confirm the certificate files exist and have proper permissions:
sudo ls -l /etc/letsencrypt/live/pumaportal.com/
sudo stat /etc/letsencrypt/live/pumaportal.com/fullchain.pem
sudo stat /etc/letsencrypt/live/pumaportal.com/privkey.pem
The output should show:
- Readable by Nginx worker process (typically www-data or nginx user)
- Symbolic links pointing to valid files in /etc/letsencrypt/archive/
- No permission errors when accessing
Sometimes the issue stems from inheritance problems. Let's examine a more robust SSL configuration:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name pumaportal.com www.pumaportal.com;
# Absolute paths with fallback
ssl_certificate /etc/letsencrypt/live/pumaportal.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pumaportal.com/privkey.pem;
# Verify certificate loading
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
location / {
proxy_pass http://localhost:2000;
include proxy_params;
}
}
Common fixes include:
# Fix symlinks if needed
sudo ln -sf /etc/letsencrypt/archive/pumaportal.com/fullchain1.pem /etc/letsencrypt/live/pumaportal.com/fullchain.pem
sudo ln -sf /etc/letsencrypt/archive/pumaportal.com/privkey1.pem /etc/letsencrypt/live/pumaportal.com/privkey.pem
# Set proper permissions
sudo chown -R root:root /etc/letsencrypt/live/
sudo chown -R root:root /etc/letsencrypt/archive/
sudo chmod -R 755 /etc/letsencrypt/live/
sudo chmod -R 755 /etc/letsencrypt/archive/
Use these diagnostic commands:
# Test configuration
sudo nginx -t
# Check loaded configuration
sudo nginx -T | grep ssl_certificate
# Verify Nginx can read files
sudo -u www-data cat /etc/letsencrypt/live/pumaportal.com/fullchain.pem > /dev/null
sudo -u www-data cat /etc/letsencrypt/live/pumaportal.com/privkey.pem > /dev/null
After making changes, follow this reload sequence:
sudo systemctl stop nginx
sudo systemctl start nginx
sudo journalctl -u nginx --no-pager -n 50