Nginx allow only root and api locations
Asked Answered
M

2

8

I have a server configured as a reverse proxy to my server. I want to reject all the requests except to two locations, one for root and another the api root.

so the server should only allow requests to the given paths

example.com/ (only the root)
example.com/api/ (every url after the api root)

The expected behaviour is that the server should reject all the below possibilities.

example.com/location
example.com/location/sublocation
example.com/dynamic-location

my current nginx configuration,

server {

   # server configurations

   location / {

        # reverse proxy configurations

    }

}

How do I set up this configuration?

Marmoset answered 9/2, 2018 at 9:31 Comment(3)
Are any resource files (css/js) served through the reverse proxy? Your list of allowed requests should include those.Skateboard
@RichardSmith only api is served through the given server. So only the server should be accessible at the pointed locations.Marmoset
@Deena, any feedback?Margiemargin
M
12

Here it is:

   location = / {
        # would serve only the root
        # ...
    }

    location /api/ {
        # would serve everything after the /api/
        # ...
    }

You need a special '=' modifier for the root location to work as expected

From the docs:

Using the “=” modifier it is possible to define an exact match of URI and location. If an exact match is found, the search terminates. For example, if a “/” request happens frequently, defining “location = /” will speed up the processing of these requests, as search terminates right after the first comparison.

Margiemargin answered 11/2, 2018 at 18:11 Comment(1)
i want rule, if someone enter "/api/123" it should return 403, everything except "/api/" shoud return 403Pinchcock
O
6

You could use an if statement to test for $request_uri being equal to root, or starting from /api/, all within the same location statement, or within the server context:

if ($request_uri !~ ^/$|^/api/) {return 403;}

However, alternatively, due to the way processing is done, the most efficient way with nginx would be to have 3 separate location directives, each handling one of the 3 possibilities — the / root exact match, the /api/ prefix, and then all the other stuff, as per http://nginx.org/r/location.

Additionally, if you also require that the root location prohibit the the query string, you can either test for $is_args (or $args/$query_string as appropriate), or, outright test whether the whole request URL is exactly / or whether it has anything more to it (note that location directives themselves don't operate based on $request_uri, but based on $uri, which are slightly different).

location = / {
    # handle root
    if ($request_uri != "/") {
        # ensure $query_string and $is_args are not allowed
        return 403 "<h1>403: query_string not allowed</h1>\n";
    }
}
location /api/ {
    # handle the /api/ prefix
}

location / {
    # handle everything else
    return 403;
}
Opia answered 11/2, 2018 at 21:56 Comment(6)
why do you suggest to use if + regexp for this case?Margiemargin
I do not suggest using if + regex, I simply provide it as an option, in case that's what you want.Opia
But how will the if conditional ever match if the location references only the root url? I don't think that's correct.Skeet
To say nothing of the fact that you're using if inside a location block - which is highly controversial: nginx.com/resources/wiki/start/topics/depth/ifisevilSkeet
@Skeet it's literally explained in parenthesis why if within the location = / does work! The ifisevil page, likewise, explains that my code is 100% correct and 100% safe! Please kindly don't downvote answers you don't understand just because you think they might not work, especially after many others have confirmed the answer does work. Also, please kindly don't link to pages you haven't read just because the title is catchy. :-)Opia
I am not dogmatic, I started testing it myself directly and I still thought you were wrong for a while until I figured a url that would match the if. Unfortunately I cannot rescind my vote now because of a seemingly random rule: "You last voted on this answer Sep 21 at 12:14. Your vote is now locked in unless this answer is edited."Skeet

© 2022 - 2024 — McMap. All rights reserved.