Why do I get 404 on nginx reverse proxy?

Viewed 11869

Below is my config and I'm getting 404 on all routes defined apart from the well-known route and I don't understand why.

If I make a request to http://example.tech/connect I get a 404 and if I make a request to http://api.example.tech I also get a 404.

I can't see where I've gone wrong as this looks like it should work!

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    error_log  /var/log/nginx/error.log  warn;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    #REMOVE REFERENCE TO FILES THAT HAVE  "server" and "location" blocks in them so we can do it all in this file
    #include /etc/nginx/conf.d/*.conf;

    # issue with ip and the nginx proxy
    real_ip_header X-Forwarded-For;
    set_real_ip_from 0.0.0.0/0;

    server {
        listen 80;
        listen [::]:80;
        server_name example.tech;

        location /.well-known/openid-configuration {
            proxy_pass https://myapp.net;

            proxy_redirect off;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection keep-alive;
            #proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header X-Forwarded-Host $host;
            #proxy_set_header X-Forwarded-Proto $scheme;
            client_max_body_size 10m;
            client_body_buffer_size 128k;
            proxy_connect_timeout 90;
            proxy_send_timeout 90;
            proxy_read_timeout 90;
            proxy_buffers 32 4k;
        }

        location /connect {
            proxy_pass https://myapp.net;

            proxy_redirect off;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection keep-alive;
            #proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header X-Forwarded-Host $host;
            #proxy_set_header X-Forwarded-Proto $scheme;
            client_max_body_size 10m;
            client_body_buffer_size 128k;
            proxy_connect_timeout 90;
            proxy_send_timeout 90;
            proxy_read_timeout 90;
            proxy_buffers 32 4k;
        }

        location /auth {
            proxy_pass https://myapp.net;

            proxy_redirect off;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection keep-alive;
            #proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header X-Forwarded-Host $host;
            #proxy_set_header X-Forwarded-Proto $scheme;
            client_max_body_size 10m;
            client_body_buffer_size 128k;
            proxy_connect_timeout 90;
            proxy_send_timeout 90;
            proxy_read_timeout 90;
            proxy_buffers 32 4k;
        }
    }

    server {
        listen 80;
        listen [::]:80;
        server_name api.example.tech;

        location /auth/ {
            proxy_pass https://myapp.net;

            proxy_redirect off;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection keep-alive;
            #proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header X-Forwarded-Host $host;
            #proxy_set_header X-Forwarded-Proto $scheme;
            client_max_body_size 10m;
            client_body_buffer_size 128k;
            proxy_connect_timeout 90;
            proxy_send_timeout 90;
            proxy_read_timeout 90;
            proxy_buffers 32 4k;
        }
    }
}
4 Answers

Needed a forward slash on the end of the proxy_pass for some reason

You need a specific uri in proxy_pass directive, not a backslash. But in your case here, a backslash is acting as the specific uri. Nginx replaces '/auth'(for example) with '/'(you've added).

In fact, the answer you put is right, turning proxy_pass http://myapp.net; to proxy_pass http://myapp.net/;.

The reason is that proxy_pass would work in two different ways with/without a specific uri. More details about this directive on nginx.org. Blow is some content quoted in that link.

  • If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:

    location /name/ {
    proxy_pass http://127.0.0.1/remote/;
    }

  • If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI:

    location /some/path/ {
    proxy_pass http://127.0.0.1;
    }

In your case, without URI in proxy_pass directive, so /auth would be passed to backend server. Unfortunately, your backend server does not have the /auth resource, so 404 is returned. If your backend server does have /auth to be processed, you would never get 404 error while requesting uri /auth.

Here are two examples, which hopefully clarify things.

 location /some-path {
    proxy_pass http://server:3000;
 }

In this case the proxied server (target) must handle the route /some-path. If handling something else, like / only, it will return an error to Nginx.

One solution is to add a trailing / e.g.:

 location /some-path {
    proxy_pass http://server:3000/;
 }

Now requests sent to /some-path can (and must) be handled by the route / on the proxied server side. However, this may cause issues with some servers. For example, with Express, curl localhost/some-path would be handled fine by Express, whereas curl localhost/some-path/ would cause Express to return Cannot GET //.

This might be different for your target server, but the principle is the same: if you specify the server only, the full path in location is passed to the server, so it must be handled accordingly.

This is my case how I've get 404 instead of 502:

# let's define some proxy pass
location ~ /.well-known/acme-challenge {
    proxy_pass http://127.0.0.1:5080; # this backend doesn't exist which leads to 502
    proxy_set_header Host $host;
}

# this is a default directives
error_page   500 502 503 504  /50x.html; # this is a reason to redirect 502 to 50x.html
location = /50x.html { # but this file doesn't exist in root so we get 404 instead of 502
    root   /usr/share/nginx/html;
}
Related