Skip to content

How to resolve '400 bad request' with Nginx?

How to resolve 400 Bad Request error when using Nginx as a reverse proxy?

Problem

The original nginx.conf file content

nginx.conf
http {
upstream myserver {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
server {
listen 8000;
server_name 127.0.0.1;
location / {
proxy_pass http://myserver;
}
}
}

I run three HTTP server instances on one server, and I use Nginx as a reverse proxy to load balance the requests to the backend HTTP services.

image-20200910145002711

When I start Nginx, I get this:

Terminal window
HTTP/1.1 400 Bad Request =>
Server => nginx

I use curl to debug the HTTP request and response:

Terminal window
curl -v http://127.0.0.1:8000/
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:8000
>
< HTTP/1.1 400 Bad Request
< Server: nginx
....
<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request</h2>
<hr><p>HTTP Error 400.</p>
</BODY></HTML>

Solution #1

When Nginx returns a 400 (Bad Request) error, it logs the reason into the error log at the “info” level. Hence, an obvious way to find out what’s going on is to configure error_log to log messages at the “info” level and take a look at the error log when testing.

You should open the debug log by adding this line to nginx.conf:

nginx.conf
error_log /var/log/nginx/error.log debug;

Solution #2

Some servers may require additional HTTP headers to be set in the HTTP request. You can add some useful HTTP headers by using proxy_set_header like this:

proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

According to the Mozilla documentation:

  • The Host Header: Specifies the domain name of the server (for virtual hosting) and (optionally) the TCP port number on which the server is listening.
  • X-Real-IP: Lets Nginx pass the request to the backend with the real client IP address. Note that this module is not built by default and should be enabled with the --with-http_realip_module configuration parameter.
  • X-Forwarded-For: Identifies the originating IP addresses of a client connecting to a web server through an HTTP proxy or a load balancer.

The final nginx.conf

nginx.conf
error_log /var/log/nginx/error.log debug;
http {
upstream myserver {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
server {
listen 8000;
server_name 127.0.0.1;
location / {
proxy_pass http://myserver/;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}

Summary

In this post, we explored how to resolve the “400 Bad Request” error when using Nginx as a reverse proxy. The key steps include enabling debug logging to identify the root cause and setting necessary HTTP headers such as Host, X-Real-IP, and X-Forwarded-For to ensure proper communication with backend servers. By following these steps, you can effectively troubleshoot and resolve this common issue.

Final Words + More Resources

My intention with this article was to help others who might be considering solving such a problem. So I hope that’s been the case here. If you still have any questions, don’t hesitate to ask me by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!