Deny all location ... except

Francis Daly francis at
Mon Oct 26 13:00:10 UTC 2020

On Wed, Oct 21, 2020 at 03:50:03PM -0300, Rejaine Silveira Monteiro wrote:

Hi there,

> I want to deny all access from external network to /prod and /hml
> locations, except from some arguments like  "?TEST" or "=TEST"

I don't see a straightforward way to do this, I'm afraid.

For a non-straightforward way: It is possible to use "map" to create a
variable to indicate whether or not you want this request to be blocked;
and then use that variable instead of your allow/deny lists. But that will
only be useful if you can find patterns that correctly match everything
you want in the block/no-block decision.

(And it is sort-of doing in config, what the application already has
facilities to do -- but your special use case might make that worthwhile.)

> https:/*  (allow to localnet, deny to external users), but...
> https:/   (allo to all)
> https:/ (allow to all)
> https:/ (allow to all)

For example, if your version of "localnet" can be expressed in a small
number of regex patterns, then you could try something like

  map "$remote_addr-$request_uri" $block_this_request {
    default 1;
    ~^127\.0\.0\.1-/ 0;

which, when used, would have the effect of allowing everything from and blocking everything else. Your case might want something
like ~^192\.168\. to allow addresses that match that pattern.

(If your "localnet" is not simple, then "geo" might be usable to set an
always-allow variable based on source IP instead; and *that* could be
used in the continuation of this example.)

Next, that same "map" should include whatever patterns you want to allow
from anywhere -- perhaps the string TEST anywhere in the url, or the
string TEST= after a ? in the url; or even a complete list of urls or
url prefixes that you want to allow; and set the $block_this_request
variable to 0 in those cases. For example, for "/TEST/" or "TEST=" or
"=TEST" anywhere in the url, you could add the three lines

  ~/TEST/ 0;
  ~TEST= 0;
  ~=TEST 0;

inside the map.

> I tried to use something like  " if ($args = TEST) {  allow all;}",
> but Nginx gives error " directive is not allowed here"

Now that you have set $block_this_request: in the two location{}s that
you want it to take effect, remove the "allow" and "deny" lines, and
instead add

  if ($block_this_request) { return 403; }

which should have the same effect as the previous deny.

> location /prod  {
>     allow localnet;
>    deny all;
>   proxy_pass http://web1.domain:8080/prod;
> }
> location /hml  {
>    allow localnet;
>    deny all
>   proxy_pass http://web1.domain:8081/hml;
> }
> I appreciate any help

It does not strike me as especially elegant; but if it does what you want,
efficiently enough for your use case, it may be adequate. At least until
someone suggests an alternative.

Good luck with it,

Francis Daly        francis at

More information about the nginx mailing list