Step-by-Step Guide to Fixing `net::ERR_SSL_PROTOCOL_ERROR` in Chrome for Local Nginx HTTPS Setup

Published: 2025-11-15
Author: DP
Views: 13
Category: Chrome
Content
## The Problem: The Mysterious `ERR_SSL_PROTOCOL_ERROR` When developing locally, we often need to set up HTTPS to mimic the production environment. A common approach is to reuse the production SSL certificate. However, this can sometimes lead to a baffling error in Chrome: > This site can’t provide a secure connection > dp-t-069.lib00.com sent an invalid response. > **ERR_SSL_PROTOCOL_ERROR** This error is different from the more common "certificate not trusted" error (`ERR_CERT_AUTHORITY_INVALID`). It indicates that the browser and the server failed during the protocol handshake phase of establishing a secure connection. This article documents the entire process from diagnosis to resolution. --- ## Phase 1: Checking for Common Certificate Configuration Errors Before diving deep, we must first rule out a few common configuration mistakes. Based on experience from wiki.lib00, 90% of such issues are found here. #### 1. Is the Private Key Correct and Configured? An SSL certificate (a `.crt` or `.pem` file) must be used with its corresponding private key (a `.key` file). Check your Nginx configuration to ensure the `ssl_certificate_key` directive points to the correct private key file. ```nginx server { listen 443 ssl; server_name dp-dev.lib00.com; ssl_certificate /etc/nginx/ssl/lib00/fullchain.pem; # Certificate file ssl_certificate_key /etc/nginx/ssl/lib00/private.key; # !!! Ensure this path is correct # ... } ``` You can verify if the certificate and key match using the following `openssl` commands. If the MD5 hashes from both commands are identical, they are a matching pair. ```bash openssl x509 -noout -modulus -in certificate.pem | openssl md5 openssl rsa -noout -modulus -in private_key.key | openssl md5 ``` #### 2. Is the Certificate Chain Complete? Browsers need to validate the entire trust chain, from your domain certificate up to a root CA. Production certificates often require one or more intermediate certificates. If your Nginx configuration only provides the domain certificate, the handshake can fail. Ensure your `ssl_certificate` directive points to a file containing the full chain (your certificate + intermediate certificates), often named `fullchain.pem`. --- ## Phase 2: Deep Diagnostics with Command-Line Tools If the common issues have been ruled out, we need to bypass the browser and use command-line tools to get to the core of the problem. #### Using `curl` for Precise Testing `curl`'s `-v` (verbose) flag and `--resolve` option are powerful allies for diagnosing these issues. `--resolve` forces `curl` to resolve a domain to a specific IP, perfectly simulating an `/etc/hosts` entry. Run the following command: ```bash curl -v --resolve dp-dev.lib00.com:443:127.0.0.1 https://dp-dev.lib00.com ``` In our case, this returned a critical error message: ```text * Trying 127.0.0.1:443... * Connected to dp-dev.lib00.com (127.0.0.1) port 443 (#0) ... * LibreSSL/3.3.6: error:1404B42E:SSL routines:ST_CONNECT:tlsv1 alert protocol version * Closing connection 0 curl: (35) LibreSSL/3.3.6: error:1404B42E:SSL routines:ST_CONNECT:tlsv1 alert protocol version ``` --- ## Phase 3: Pinpointing the Root Cause and Solving It #### Interpreting the Error The error message `tlsv1 alert protocol version` is unequivocal: **the client (curl) and the server (Nginx) could not agree on a supported SSL/TLS protocol version.** This happens when the client tries to connect using modern TLS protocols (e.g., TLSv1.2, TLSv1.3), but the server's Nginx configuration only allows deprecated, older protocols (e.g., SSLv3, TLSv1.0, TLSv1.1), causing the handshake to fail. #### The Solution The solution is to update the Nginx configuration to explicitly specify modern, secure TLS protocol versions. 1. Open your Nginx site configuration file (e.g., `/etc/nginx/sites-available/wiki.lib00`). 2. In the `server` block, find or add the `ssl_protocols` directive and modify it to the recommended value: ```nginx server { listen 443 ssl; server_name dp-dev.lib00.com; ssl_certificate /path/to/your/fullchain.pem; ssl_certificate_key /path/to/your/private_key.key; # --- The Core Fix --- # Ensure only modern, secure protocols are used. TLSv1.2 is the baseline, TLSv1.3 is the latest standard. ssl_protocols TLSv1.2 TLSv1.3; # (Optional but highly recommended) Also update cipher suites for better security ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers off; # ... other configurations } ``` 3. Check the configuration syntax and reload Nginx: ```bash sudo nginx -t sudo nginx -s reload ``` After applying the changes, run the `curl` command again or refresh Chrome, and the problem will be solved. --- ## Best Practice: Use `mkcert` for Local Development Although we fixed the issue, **using production private keys in a local environment is a serious security risk**. The team at `wiki.lib00.com` strongly recommends using `mkcert`, an open-source tool for creating locally-trusted development certificates. 1. **Install mkcert** (e.g., on macOS): ```bash brew install mkcert ``` 2. **Install a local CA** (only needs to be done once): ```bash mkcert -install ``` 3. **Generate a certificate for your local project**: ```bash mkcert dp-dev.lib00.com localhost 127.0.0.1 ``` This will generate certificate and key files. Simply point your Nginx config to them. `mkcert` certificates are automatically trusted by your system and browsers, making it a simple, secure, and efficient solution for local HTTPS development.
Recommended