Nginx is trying to serve plain HTTP requests on the port configured for HTTPS, and the client’s browser is getting confused.

Common Causes and Fixes

  1. Incorrect listen directive in Nginx configuration.

    • Diagnosis: Check your Nginx configuration files (e.g., /etc/nginx/nginx.conf and files in /etc/nginx/sites-available/ or /etc/nginx/conf.d/). Look for listen directives within your server blocks.
    • Cause: You might have accidentally configured a server block to listen on port 443 (the standard HTTPS port) without specifying ssl or http2, or you might have a separate server block listening on port 80 (HTTP) that’s catching requests intended for your HTTPS site. The most common mistake is having a default server block on port 443 that isn’t set up for SSL.
    • Fix: Ensure your HTTPS server block explicitly lists listen 443 ssl http2; (or listen 443 ssl; if not using HTTP/2). For your HTTP server block (if you have one for redirects or plain HTTP access), ensure it listens on listen 80; and redirects to HTTPS.
      server {
          listen 80;
          server_name example.com;
          return 301 https://$host$request_uri;
      }
      
      server {
          listen 443 ssl http2;
          server_name example.com;
      
          ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
          ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
          # ... other SSL settings
      }
      
    • Why it works: Nginx uses the listen directive to bind to specific IP addresses and ports. By explicitly defining listen 443 ssl http2;, you tell Nginx to expect SSL/TLS encrypted traffic on that port. Without ssl, it defaults to plain HTTP, leading to the mismatch. The HTTP block with return 301 ensures all HTTP traffic is correctly redirected to HTTPS.
  2. Missing or incorrect SSL certificate configuration.

    • Diagnosis: In your Nginx configuration for the HTTPS server block, verify the paths to ssl_certificate and ssl_certificate_key.
    • Cause: If Nginx is configured to listen on 443 ssl but the certificate files are missing, inaccessible, or misconfigured, it can fail to establish an SSL connection. This can manifest as the browser receiving an unexpected HTTP response on the HTTPS port.
    • Fix: Ensure the ssl_certificate and ssl_certificate_key directives point to valid, readable certificate files. For example:
      ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
      ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
      
      If using Certbot, these paths are typically managed automatically. Run sudo certbot --nginx to reconfigure or renew.
    • Why it works: Nginx needs valid SSL certificates to perform the TLS handshake required for HTTPS. If these are not found or are invalid, the handshake fails, and Nginx might fall back to serving whatever content it has configured for that port as plain HTTP, confusing the browser which expects encryption.
  3. Conflicting server_name directives or duplicate server blocks.

    • Diagnosis: Review all server blocks in your Nginx configuration for the relevant domain name.
    • Cause: If you have multiple server blocks that could potentially match a request (e.g., one on port 80 and one on port 443 for the same server_name), or if you have duplicate server blocks with the same server_name and listen directives, Nginx might pick the wrong one. This is especially true if a default server is not clearly defined.
    • Fix: Ensure each server_name is uniquely handled by a specific server block. Use _ for a default server block if necessary. For example, a strong default server for HTTP could be:
      server {
          listen 80 default_server;
          listen [::]:80 default_server;
          server_name _; # Catches all other hostnames on port 80
          return 301 https://$host$request_uri;
      }
      
      And ensure your specific server_name example.com; blocks are correctly configured for their respective ports.
    • Why it works: Nginx matches incoming requests to server blocks based on listen directives and server_name values. Ambiguity can lead to Nginx selecting a block that doesn’t have SSL enabled when it should, or serving the wrong content entirely. Explicitly defining default servers and unique server_name matches resolves these conflicts.
  4. HTTP/2 not enabled or incorrectly configured.

    • Diagnosis: Check the listen directive in your HTTPS server block.
    • Cause: Browsers often expect HTTP/2 for HTTPS connections to improve performance. If you have listen 443 ssl; but not http2, or if Nginx wasn’t compiled with HTTP/2 support, some clients might misinterpret the connection. While less common as a direct cause of plain HTTP on HTTPS port, it can contribute to connection issues.
    • Fix: Ensure your listen directive includes http2 if you intend to use it:
      listen 443 ssl http2;
      
      If Nginx was not compiled with the --with-http_v2_module flag, you’ll need to recompile Nginx or install a pre-compiled version that supports it. Most modern Nginx packages do.
    • Why it works: HTTP/2 is a protocol negotiation that happens during the TLS handshake. Explicitly enabling it tells Nginx to advertise and support HTTP/2 capabilities, ensuring compatibility with clients that expect it on HTTPS connections.
  5. Firewall blocking or misconfigured Nginx worker processes.

    • Diagnosis: Check firewall rules (e.g., sudo ufw status, sudo iptables -L). Also, check Nginx worker process status.
    • Cause: A firewall might be interfering with Nginx’s ability to bind to port 443, or it could be configured to allow HTTP traffic on port 443. Less likely, but possible, are issues with Nginx worker processes not having the correct permissions to bind to privileged ports (<1024) if Nginx is not run as root (though typically Nginx starts as root and drops privileges).
    • Fix: Ensure your firewall allows traffic on port 443:
      sudo ufw allow 443/tcp
      sudo ufw reload
      
      Verify Nginx is running and its worker processes are healthy. If Nginx is not running as root, ensure it’s started via a process manager that handles initial port binding or that the user Nginx runs as has CAP_NET_BIND_SERVICE capabilities.
    • Why it works: Firewalls act as gatekeepers. Allowing traffic on port 443 ensures that incoming HTTPS requests can reach the Nginx process listening on that port. Correct process permissions ensure Nginx can actually bind to the required network socket.
  6. Browser cache or local DNS issues.

    • Diagnosis: Clear your browser’s cache, try an incognito/private browsing window, or test from a different device/network. Use curl -v https://example.com to inspect the handshake.
    • Cause: Sometimes, the browser or local network caches an old, incorrect response or DNS record, leading it to believe it should be making a plain HTTP request or that the server is not responding correctly to HTTPS.
    • Fix: Clear browser cache. Try curl -v https://your_domain.com. Look for HTTP/1.1 200 OK (which is bad for HTTPS) or TLS handshake errors. If curl also fails, the issue is server-side. If curl works but the browser doesn’t, it’s likely a browser or local cache problem.
    • Why it works: Eliminating local caching layers ensures you are testing against the live server configuration, helping to isolate whether the problem is with Nginx or the client’s environment.

After fixing these, the next error you might encounter is a "SSL certificate verification failed" if your certificate is expired or not trusted by the client’s CA.

Want structured learning?

Take the full Nginx course →