82

I am trying to pass off all calls to /api to my webservice but I keep getting 404s with the following config. Calls to / return index.html as expected. Does anyone know why?

upstream backend{
    server localhost:8080;
}

 server {

    location /api {
        proxy_pass http://backend;
    }

    location / {
        root /html/dir;
    }
}

More info here

adept@HogWarts:/etc/nginx/sites-available$ curl -i localhost/api/authentication/check/user/email
HTTP/1.1 404 Not Found
Server: nginx/1.2.1
Date: Mon, 22 Apr 2013 22:49:03 GMT
Content-Length: 0
Connection: keep-alive

adept@HogWarts:/etc/nginx/sites-available$ curl -i localhost:8080/authentication/check/user/email
HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 22 Apr 2013 22:49:20 GMT
Transfer-Encoding: chunked

{"user":["false"],"emailAddress":["false"]}
bschlueter
  • 3,817
  • 1
  • 30
  • 48
Roge
  • 3,294
  • 2
  • 20
  • 19

6 Answers6

175

This

location /api {
    proxy_pass http://backend;
}

Needs to be this

location /api/ {
    proxy_pass http://backend/;
}
bschlueter
  • 3,817
  • 1
  • 30
  • 48
Roge
  • 3,294
  • 2
  • 20
  • 19
  • 21
    Seems to fix the issue, but an explanation of what difference this makes would be nice. – user1338062 Dec 31 '14 at 11:06
  • This doesn't solve the problem for me. In fact it makes it worse and gives me a `ERR_TOO_MANY_REDIRECTS` in chrome. – 0xAffe Aug 08 '15 at 08:53
  • 1
    0xAffe - mind the both slashes at the and of the path and proxy_pass url. The too many redirects sometimes happen if you missed one of the slashes – szydan Feb 27 '16 at 13:02
  • 2
    oh wow. i had it working without the trailing slash for other backends, but this one needed it for some reason. – fei0x Feb 13 '18 at 18:17
  • 3
    Nginx config is really confusing. So how this slash in the end matters? – shuangwhywhy Mar 12 '18 at 13:34
  • That does not fix it. – Soerendip Apr 02 '19 at 21:43
  • Hi should this be added in default or nginx.conf ? – kd12345 Jan 26 '21 at 15:17
  • @user1338062 the explanation of what difference this makes is in one of the below answers. It has to do with whether nginx alters the path or not. – Joseph Summerhays Jan 10 '22 at 17:00
  • If a location is defined by a prefix string that ends with the slash character, and requests are processed by one of proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, or grpc_pass, then the special processing is performed. In response to a request with URI equal to this string, but without the trailing slash, a permanent redirect with the code 301 will be returned to the requested URI with the slash appended. – ByteVictor Feb 07 '23 at 20:29
  • It is strange, i've been two hours breaking my head, to finally find that unlike apache, nginx requires the trailing slash to work. – Hans Poo Jun 01 '23 at 20:31
67

Just want to remind others that the slash(backend*/*) after your proxy_pass url is very important!

if the config is

location /api/ {
    proxy_pass http://backend;
}

and you visit http://abc.xyz/api/endpoint, you would be directed to http://backend/api/endpoint;

if the config is

location /api/ {
    proxy_pass http://backend/;
}

and you visit http://abc.xyz/api/endpoint, you would be directed to http://backend/endpoint.

That's the difference.

For more, refer to: Nginx reverse proxy return 404

d0zingcat
  • 929
  • 8
  • 10
14

By some reason proxy_pass in Nginx cuts header "Host" before passing to upstream, and request catches by default server, and even proxy_header_pass doesn't helps, so I've to explicitly set it:

location / {
    proxy_set_header Host $host;
    proxy_pass  http://backend;
}
Oleg Neumyvakin
  • 9,706
  • 3
  • 58
  • 62
5

Try to troubleshoot step by step to identify which point that possibly cause the issue. Here are some possible mistakes:

The Nginx configuration changed but Nginx did not reload it

This might be occur when you override the nginx.conf file but didn't trigger nginx to reload the config. Might frequently occur to docker user.
To reload the nginx configs, while in the Nginx host, execute command: nginx -s reload
With docker: docker exec <container_name> nginx -s reload
Ref: Controlling NGINX Processes at Runtime

The Nginx default config is overriding yours

This might occurs when nginx.conf also include the default Nginx config and it accidentally override yours, carefully check your nginx.conf if it includes any default config path.
E.g: include /etc/nginx/conf.d/*.conf;, which will also load the nginx default config at the following address
enter image description here
If this is the case, comment out (or remove) this include config statement from your nginx.conf file.

Verify Nginx configuration

Verify the actual config being applied with command nginx -T, this will trigger Nginx to test and print out the configuration, check if the configuration output match your expected result:
Reference: Nginx commandlines
You should see something like the following

root@22a2e5de75ba:/etc/nginx/conf.d# nginx -T
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# configuration file /etc/nginx/nginx.conf:
user  nginx;
worker_processes  auto;

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


events {
    worker_connections  1024;
}

http {
    server {
        server_name "localhost";
        listen 80;
        location /todo_server/ {
            proxy_pass http://jsonplaceholder.typicode.com;
        }
    }
    # 
    
    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;
    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;
    #gzip  on;
    # include /etc/nginx/conf.d/*.conf;
}

Problem with Nginx proxy_pass configuration

Similar to the previous answer in this thread
This will result in unexpected proxy mapping if you specify the trailing slash / at the end of the URI.
First, see the completed: Nginx proxy_pass document
I'll use the API http://jsonplaceholder.typicode.com/todos/ from jsonplaceholder for demo (it actually serves response for you to test)

With trailing slash
The trailing slash at the end indicate that this proxy_pass directive is specified with a URI. In this case, 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.

Example: with the following config, which is understood as specified with a URI, will resulted in this mapping

location /path1/ {
    proxy_pass http://jsonplaceholder.typicode.com/todos/;  
    # Requesting http://localhost:8080/path1/ will proxy to => http://jsonplaceholder.typicode.com/todos/
    # Requesting http://localhost:8080/path1/1/ will proxy to => http://jsonplaceholder.typicode.com/todos/1
}

location /path2/ {
    proxy_pass http://jsonplaceholder.typicode.com/;
    # Requesting http://localhost:8080/path2/todos/ will proxy to => http://jsonplaceholder.typicode.com/todos/
}

Without trailing slash
Without the trailing slash /, it's understood as no URI scheme, 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 /todos/ {
    proxy_pass http://jsonplaceholder.typicode.com; 
    # Requesting : http://localhost:8080/todos/ will proxy to ==> http://jsonplaceholder.typicode.com/todos/
    # Requesting : http://localhost:8080/todos/1 will proxy to ==> http://jsonplaceholder.typicode.com/todos/1
}

Please also see the completed answer from @dayo and also answer by Richard Smith

ThangLeQuoc
  • 2,272
  • 2
  • 19
  • 30
3

Please check that if you have deleted default.conf file from site-enabled folder. Run the command if you are in debian based ubuntu system

sudo rm /etc/nginx/sites-enabled/default

It worked for me.

Sihat Afnan
  • 742
  • 7
  • 14
2

I forgot to listen on PORT 80, fixed it.

"http" part of nginx config, at: /etc/nginx/nginx.conf, is below:

http {
    server {
        listen 192.111.111.11:80;
        location /path1/ {
            proxy_pass http://127.0.0.1:3000/path1/
        }
    }
}

Now, accessing
http://192.111.111.11/path1/
will get result of accessing
http://127.0.0.1:3000/path1/

NOTE:
Replace the 192.111.111.11 with your IP address in the above.
Run "ifconfig" command, the "inet addr" part will give your IP address

Manohar Reddy Poreddy
  • 25,399
  • 9
  • 157
  • 140