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.
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.
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.
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;
}
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
.
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!