Looking for a specific post? Checkout the Blog Index.

By Kimserey Lam with

Nginx Proxy Pass

May 10th, 2019 - written by Kimserey with .

In a previous post, we saw how we could host an ASP.NET Core application behind Nginx. We saw that Kestrel works as a selfhost webserver and that in order to get request forwarded to it, we need to proxy them using the location and proxy_pass directives. Today we will look into some details regarding path handling, ensuring that our requests are forwarded properly.

URI Rules

The URI rule followed by Nginx can be summarized by; If the proxied URL contains a URI, the matching path from the location directive will be replaced by the proxied URL and the remaining path will be appended, else the full path is appended to the proxied URL.

The URI represents what comes after the host including any trailing slash. http://localhost:5000 does not have a URI while http://localhost:5000/ has a URI ‘/’. This point has major implications on the behavior of the request forwarding.

Valid and Invalid Examples

Now let’s assume that we have setup an application running on http://locahost:5000 with two endpoints:

  • /home,
  • /test/home.

Both endpoints respectively accessible on http://localhost:5000/home and http://localhost:5000/test/home.

If we want to be able to proxy all calls from /api/[...] to our application, we need to use the location directive combined with proxy_pass from Nginx. But as we are about to see, combining the two can be tricky and there are specific scenarios that we need to be aware of.

Valid proxy_pass configuration

The following proxy_pass configuration is setup with a URI which will be replaced by the matched path.

1
2
3
location /api/ {
    proxy_pass http://localhost:5000/;
}

http://localhost/api/home will match the location /api/ and will be proxied to http://localhost:5000/home as http://localhost/api/ gets replaced by http://localhost:5000/ leaving the rest of the path home to be appended. Similarly the following will forward properly /api/home to /test/home:

1
2
3
location /api/ {
    proxy_pass http://localhost:5000/test/;
}

Lastly it’s also possible to get http://localhost/api/home forwarded to http://localhost:5000/test/home with the following configuration.

1
2
3
location /api {
    proxy_pass http://localhost:5000/test;
}

Invalid proxy_pass configuration

The configuration will not work if the location and the proxied URL are missing a trailing slashes causing the whole URI to be appended to the URL.

1
2
3
location /api {
    proxy_pass http://localhost:5000;
}

This is due to the fact that the call will be forwarded as http://localhost:5000/api/home which does not exists. Providing a trailing slash on the location but not on the proxied URL will also not work for the same reason as above.

1
2
3
location /api/ {
    proxy_pass http://localhost:5000;
}

This is due to the fact that the call will be forwarded as http://localhost:5000/api/home as well. The opposite will also not work, providing a trailing slash on the proxied URL but not on the location.

1
2
3
location /api {
    proxy_pass http://localhost:5000/;
}

This is due to the fact that the call will be forwarded as http://localhost:5000//home which does not exists. Location without trailing slash but proxied URL with URI will result in /test//thome.

1
2
3
location /api {
    proxy_pass http://localhost:5000/test/;
}

Lastly trailing slash in location together with URI will not work:

1
2
3
location /api/ {
    proxy_pass http://localhost:5000/test;
}

Caused by http://localhost/api/home being proxied to http://localhost:5000/testhome as http://localhost/api/ gets replaced by http://localhost:5000/test leaving the rest of the path home to be appended hence resulting to wrong URL http://localhost:5000/testhome.

Conclusion

Today we explored different combinations between location path and proxy_pass URL and saw which were working as expected and which weren’t. We saw the rule behind how Nginx proxies URLs which allowed us to understand why certain location would be valid. Hope you liked this post, see you next time!

Designed, built and maintained by Kimserey Lam.