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
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.
When I start Nginx, I get this:
HTTP/1.1 400 Bad Request =>Server => nginx
I use curl
to debug the HTTP request and response:
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
:
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
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:
- 👨💻 The Host Header
- 👨💻 X-Real-IP Module
- 👨💻 X-Forwarded-For Header
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!