Weird redirect issue with some hosts fine on some paths but not others

We have a couple of web apps running on Docker alongside a linuxserver/letsencrypt container which reverse proxies to them. Everything is on the same machine.

The conf for each container is in proxy-confs as a subdomain and is as follows.

api.dev.brring.com:

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name api.dev.brring.com;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        resolver 127.0.0.11 valid=30s;
        set $upstream_app api.dev.brring.com;
        set $upstream_port 5001;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}

api.staging.brring.com

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name api.staging.brring.com;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        resolver 127.0.0.11 valid=30s;
        set $upstream_app api.staging.brring.com;
        set $upstream_port 5003;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}

Besides the domain names the configs are identical.

Both application servers work fine and we can connect to them using our clients.

Where it gets super weird is when we try to access the health URLs:

You can see the dev URL works as expected http https://api.dev.brring.com/actuator/health:

HTTP/1.1 200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Date: Sun, 12 Jul 2020 23:27:13 GMT
Expires: 0
Pragma: no-cache
Server: nginx/1.18.0
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

{
    "status": "UP"
}

However the staging URL http https://api.staging.brring.com/actuator/health sends us in a 302 redirect loop:

HTTP/1.1 302
Connection: keep-alive
Content-Length: 0
Date: Sun, 12 Jul 2020 23:30:02 GMT
Location: https://api.staging.brring.com/actuator/health
Server: nginx/1.18.0

Firstly are we correctly proxying to our app servers (they’re not in the same user defined bridge network as letsencrypt)?

Why would our second server work fine for everything except the health URL? (if we query it directly via localhost it works fine…)

You are not correctly reverse proxying (it works, but it’s not ideal) although that’s likely not the cause of the 302

You are currently proxying via host mapped ports. If the containers are already in the same custom bridge network, set the upstream app var to the container name (use only lowercase) and use the internal port the container is listening on.
Then in your compose yml, you can get rid of the port mapping for your app containers because all outside connections will come in through letsencrypt’s port 443 and the connection between letsencrypt and the other containers will go through the docker network.

See if that fixes the issue