Score:0

Reverse proxy returning 307 (redirect) when it shouldn't be

do flag

I'm trying to setup a reverse proxy to an application that I'm building. The application is split into two docker images. First is a web UI, which can be reached via https://example.com/

The second docker image, has base addresses that I'm interested in. The first, is https://example.com/swagger and the second is https://example.com/api

When I navigate to example.com everything works as expected. I get the application front end. When I navigate to the swagger link, again everything is working just fine, I get the swagger page. the actual address is https://example.com/swagger/index.html

However, the third part of this is that the https://example.com/api is a Rest API that I want to access, when I try to make a call to this. Or more specifically, a POST request to https://example.com/api/Authentication/login

I get a 307 response from the server which redirects the call to http://actualserver.local:7066/api/Authentication/login

I don't understand why it's doing this, as it should be getting the information just as the swagger link is doing.

Here's my nginx.conf file that I'm using to run the reverse proxy

worker_processes 1;

events { worker_connections 1024; }

http {
    client_max_body_size 0;
    sendfile on;

    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-Host $server_name;

    server {
        listen 80 default_server;

        server_name example.com;

#        location /.well-known/acme-challenge/ {
#            root /var/www/certbot;
#        }

        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2;

        ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        server_name     example.com;

        location /api {
            proxy_pass         http://actualserver.local:7066/api;
            proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection "Upgrade";
            proxy_set_header   X-Forwarded-Proto https;
            proxy_redirect     off;
        }

        location /swagger {
            proxy_pass         http://actualserver.local:7066/swagger;
            proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection "Upgrade";
            proxy_set_header   X-Forwarded-Proto https;
            proxy_redirect     off;
        }

        location / {
            proxy_pass         http://actualserver.local:3000;
            proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection "Upgrade";
            proxy_set_header   X-Forwarded-Proto https;
            proxy_redirect     off;
        }

        location /.well-known/acme-challenge/ {
            root /var/www/certbot;
        }
    }
}

What I'm looking for is to get the reverse proxy to make the call to actualserver.local, instead of returning a 307. I'm a bit out of my depth here, so any help would be appreciated.

update: I tried modifying the nginx config to see if this has any effect. Here's my updated file.

worker_processes 1;

events { worker_connections 1024; }

http { client_max_body_size 0; sendfile on;

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-Host $server_name;

upstream web-ui {
  server actualserver.local:3000;
}

upstream web-api {
    server actualserver.local:7066;
}

server {
    listen 80 default_server;

    server_name example.com;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    server_name     example.com;

    location /api {
        proxy_pass         http://web-api/api;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "Upgrade";
        proxy_set_header   X-Forwarded-Proto https;
        proxy_redirect     off;
    }

    location /swagger {
        proxy_pass         http://web-api/swagger;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "Upgrade";
        proxy_set_header   X-Forwarded-Proto https;
        proxy_redirect     off;
    }

    location / {
        proxy_pass         http://web-ui;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection "Upgrade";
        proxy_set_header   X-Forwarded-Proto https;
        proxy_redirect     off;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
}

}

The location being reported in the 307 is

https://web-api:7066/api/Authentication/login

The only place where web-api exists in the entire code base is in the nginx.conf, this cannot be from the application server. It has to be nginx that is doing this.

Score:2
ws flag

This is nothing to do with your proxy configuration - there is nothing in the config you've shown us that would return a 307 / nginx doesn't know anything about http://actualserver.local:7066/api/Authentication/login

This response is coming from the origin server.

Nginx is doing exactly what it should and relaying that back to the client.

It also demonstrates that you have not configured your origin servers correctly - they need to know the URL they are being accessed via.

Colin Dawson avatar
do flag
It's an asp.netcore webapi that I'm exposing via the /api endpoint. The /swagger endpoint is also exposed by the same application. I assumed that because swagger is working ok, that the /api would be as well. That's something for me to look into more, maybe there's something in the api.netcore stuff that I can tweak to get this working. Thank you, that gives me something that I can look into.
Colin Dawson avatar
do flag
I will vote up, when I figure out that the comment was useful and not a hinderance to solving the issue. At the moment, this is an unknown and I'm still investigating.
Colin Dawson avatar
do flag
Actually, I've just done another experiment and think that NGINX is where the issue is happening, I'll update the question with the details.
ws flag
No. Even though this config and URLs are very different from what you posted previously, the evidence still points to the origin server. Nginx doesn't know about /api/Authentication/login and the origin server will see the request hostname in the request / does not have to include it in the response.
Colin Dawson avatar
do flag
The original request is being sent to https://example.com/api/Authentication/login The nginx should be sending the request to http://actualserver.local:7066/api/Authentication/login
Colin Dawson avatar
do flag
And yep, finally after messing with this all day, I've got it working. The root problem was that the application was routing all API requests to https. But that wasn't effecting the Swagger links.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.