Tackling 421 Misdirected Request with SNI Header in Nginx

Saad Bhutto
devkind
Published in
3 min readAug 6, 2024
Photo by Scott Rodgerson on Unsplash

One challenge that frequently arises is the dreaded `421 Misdirected Request` error, especially when dealing with SSL/TLS connections and the SNI (Server Name Indication) header. In this blog post, we’ll delve into what SNI is, why the 421 error occurs, and how to handle it using Nginx.

What is SNI?

Server Name Indication (SNI) is an extension of the TLS protocol that allows a client to specify the hostname it is trying to connect to at the start of the handshake process. This is particularly useful when multiple domains are hosted on the same IP address, enabling the server to present the correct SSL certificate for the requested domain.

Without SNI, the server would not know which certificate to use, leading to potential security issues or connection failures.

Understanding the 421 Misdirected Request Error

The `421 Misdirected Request` error occurs when the server receives a request that is not appropriate for the target resource. This often happens when the server name in the request does not match the expected server name, causing confusion in SSL/TLS connections, especially when SNI is involved.

This issue is prevalent in reverse proxy setups where the proxy server needs to correctly forward client requests to different backend servers based on the SNI header.

Solving the 421 Error with Nginx

To illustrate the solution, let’s consider a scenario where we want to use Nginx as a reverse proxy to forward requests from `subdomain.company.com` to `company.central.website.io`. Here’s how we can configure Nginx to handle this, ensuring the correct SNI header is passed to avoid the 421 error.

Nginx Configuration

Below is a sample Nginx configuration file designed to tackle the 421 error by properly setting the SNI header:

server
{
listen 443 ssl;
server_name subdomain.company.com;
ssl_certificate /var/share/nginx/certs/certificate.crt;
ssl_certificate_key /var/share/nginx/certs/certificate.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
allow all;
error_log /var/log/nginx/subdomain_error.log error;
location /
{
proxy_set_header Host company.central.website.io;
proxy_set_header X-Forwarded-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;
# Remove SNI header to prevent 421 errors
proxy_set_header SNI $server_name;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_pass https://company.central.website.io;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
add_header X-Iv-Proxy-Host $proxy_host always;
}
}

Configuration Breakdown

Server Block

server {
listen 443 ssl;
server_name subdomain.company.com;

This block defines the server settings. It listens on port 443 for SSL connections and responds to requests for `subdomain.company.com`.

SSL Configuration

ssl_certificate /var/share/nginx/certs/certificate.crt;
ssl_certificate_key /var/share/nginx/certs/certificate.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;


allow all;
error_log /var/log/nginx/subdomain_error.log error;

These directives configure SSL, specifying the paths to the certificate and key files, session timeout, and the SSL protocols to use.

`allow all` permits access from any IP, and `error_log` defines where to log error messages.

Location Block

 location /
{
proxy_set_header Host company.central.website.io;
proxy_set_header X-Forwarded-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;
# Remove SNI header to prevent 421 errors
proxy_set_header SNI $server_name;
proxy_ssl_verify off;
proxy_ssl_server_name on;
proxy_pass https://company.central.website.io;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
add_header X-Iv-Proxy-Host $proxy_host always;
}

The `location /` block handles all requests to the root URL. Here, we set several headers to ensure proper forwarding of client information.

Crucially, the `proxy_set_header SNI $server_name;` directive sets the SNI header to the server name, ensuring that the correct SSL certificate is used and preventing the 421 error.

The `proxy_ssl_verify off;` directive disables SSL verification for the upstream server, while `proxy_ssl_server_name on;` ensures that SNI is enabled for the upstream connection. The `proxy_pass` directive forwards the request to the specified upstream server, and timeouts are set for various stages of the proxy connection.

Conclusion

The `421 Misdirected Request` error can be a significant hurdle when configuring Nginx as a reverse proxy, especially when dealing with SSL/TLS and SNI headers. By understanding the root cause and properly setting the SNI header in your Nginx configuration, you can ensure secure and seamless traffic routing. This setup not only resolves the 421 error but also enhances the overall security and reliability of your proxy server.

--

--