chrisdot
chrisdot

Reputation: 789

troubleshooting application behind nginx reverse proxy, as POST/PUT requests are replied with Error 400 (Bad Request)

I'm trying to host my Angular/ASP.net core 3.1 application on linux for the first time.

Nginx stands on the port 80 and serves the static files and acts as a reverse proxy for the api part which will be passed to the .NET/kestrel server.

The problem is that I systematically get a 400 status code error (Bad Request) on any web API request containing a body, like POST & PUT, but GET is ok.

I added some logs through a middleware, just to see if I can get the requests. Basically, something like:

app.Use(async (context, next) => {
    context.Request.EnableBuffering();
    string reqBody;
    using (var reader = new StreamReader(context.Request.Body))
    {
        reqBody = await reader.ReadToEndAsync();
        context.Request.Body.Seek(0, SeekOrigin.Begin);
        ms_oLogger.Debug($"Incoming request: METHOD={context.Request.Method} PATH={context.Request.Path} BODY=\"{reqBody}\"");
    }
    await next();
});

This just loggs stuff for GET requests, but nothing appears for the problematic PUT/POST requests... Can I conclude that this is only a nginx problem?

I also enabled the logs on nginx for the given "/api" location, but I can not tell what happens... How can I know which tier has generated the 400 status code?

EDIT1: I started a blank new project just with a poor Web API project containing one GET and one POST method just to check if there was something wrong with my application, but I still get the problem. So I set up a new ubuntu server (this time, ubuntu server instead of desktop version) and now it works!!! I compared configuration etc... but could not figure out what was wrong!.... But my initial question is still valid: how can I troubleshoot where the problem comes from?

EDIT2: This is my default.conf:

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                try_files $uri $uri/ =404;
        }

        location /fusion {
                root /opt/fichet/WebUI/NgApp;
        }

        location /fusion/api  {
               proxy_pass http://localhost:5000/api;
                error_log          /var/log/nginx/fusion_error_logs.log debug;
                access_log         /var/log/nginx/fusion_access.log;
                proxy_http_version 1.1;
                proxy_cache_bypass  $http_upgrade;
                proxy_set_header Upgrade           $http_upgrade;
                proxy_set_header Connection        "upgrade";
                proxy_set_header 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;
                proxy_set_header X-Forwarded-Host  $host;
                proxy_set_header X-Forwarded-Port  $server_port;
        }
}

It seems that no firewall is enabled ("sudo ufw status verbose" tells us that it is "inactive")

Upvotes: 3

Views: 4424

Answers (1)

Dirbaio
Dirbaio

Reputation: 3140

Remove these lines from your nginx config.

                proxy_cache_bypass  $http_upgrade;
                proxy_set_header Upgrade           $http_upgrade;
                proxy_set_header Connection        "upgrade";

These headers are used for WebSocket connections, and shouldn't be present for non-websocket requests. My guess is your upstream server doesn't mind them for GET requests but does for POST/PUT, for some reason.

If you are not using websockets, you can leave them removed.

If you are using websockets, you need nginx to add or not these headers based on whether the requests is websockets or not. Something like this should work:

    http {
        map $http_upgrade $connection_upgrade {
            default upgrade;
            ''      close;
        }

        server {
            ...

            location /fusion/api {
                proxy_pass ...
                ...
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection $connection_upgrade;
            }
        }

See here for more info.

Upvotes: 4

Related Questions