Score:0

How to do an nginx redirect excluding an IP address and a path?

fr flag

I need to redirect to a URL unless the user is coming from within our internal IP address or if they are accessing a particular path.

I've tried this:

location ~* /foobar {
    break;
}

location ~* / {
    if ($remote_addr != 111.222.333.444) {
        rewrite ^ https://external.tld/
    }
}

But that doesn't seem to work. That particular configuration causes a 404 when going to https://mydomain.tld/foobar and a "Welcome to nginx!" page when accessing it from within our IP address. However, accessing https://mydomain.tld/foobar outside of our IP address does properly redirect to https://external.tld/

djdomi avatar
za flag
Questions seeking installation, configuration or diagnostic help must include the desired end state, the specific problem or error, sufficient information about the configuration and environment to reproduce it, and attempted solutions. Questions without a clear problem statement are not useful to other readers and are unlikely to get good answers.
Darrell Brogdon avatar
fr flag
@djdomi What do you recommend for making the problem statement clearer?
djdomi avatar
za flag
show us nginx -T and explain what is does not work means, currently you just tell us the half way ;)
Darrell Brogdon avatar
fr flag
@djdomi Thanks. I added more clarification to what is happening with the given configuration. Unfortunately, I'm not allowed to post the results of `nginx -T`.
djdomi avatar
za flag
if it's only a single url, is a subdomain also possible?
Darrell Brogdon avatar
fr flag
No, just that one URL.
Score:1
gr flag

Since you don't want (or are not allowed) to show your full server block, I'll make some guesses. What most likely happened with your configuration? You created two additional location blocks which are used to process any incoming request. Check the location directive documentation. The only two location types that can overtake a request from regex matching location are exact location (location = /uri { ... }) and do-not-check-regex prefix location (location ^~ /prefix { ... }). Otherwise, the first regex matching location will be chosen.

Every server block has its root directory, even if it isn't specified explicitly using the root directive. It is chosen using prefix (specified at the compilation time, can be checked with the nginx -V command) and /html suffix. Lets assume your nginx prefix is /usr/share/nginx. Then your default root will be at the /usr/share/nginx/html directory, unless explicitly specified using the root /some/path directive.

Default nginx behavior when serving a request can be described as try_files $uri $uri/ =404.

Lets assume we have a https://mydomain.tld/foobar request. To serve it your first location ~* /foobar { break; } will be chosen as the first matched regex location. The first directive break means that processing the current set of ngx_http_rewrite_module directives will be stopped. But there are none of those directives (except the break one) inside this location block! Yes, that means that this break directive is useless here. Next, nginx will check for the existence of a /usr/share/nginx/html/foobar file, an index file from the /usr/share/nginx/html/foobar/ directory (default is index.html), and after both checks fails, return an HTTP 404 Not Found error.

Now lets assume we have a https://mydomain.tld/ request. Your first location block won't match it, so the second one location ~* / { ... } is chosen to process this request (this location block will match any possible valid request). If an IP address check won't pass, a redirection will take its place. But if it would pass, nginx will process your request the same way as described above, returning your default welcome index.html file from the /usr/share/nginx/html/ directory.

Looks like you don't understand how directives from the ngx_http_rewrite_module are processed. Read again the very first part of the documentation:

The break, if, return, rewrite, and set directives are processed in the following order:

  • the directives of this module specified on the server level are executed sequentially;
  • repeatedly:
    • a location is searched based on a request URI;
    • the directives of this module specified inside the found location are executed sequentially;
    • the loop is repeated if a request URI was rewritten, but not more than 10 times.

You can place your checks at the server block level:

if ($uri = /foobar) {
    break;
}
if ($remote_addr != 111.222.333.444) {
    rewrite ^ https://external.tld/
}

The above break directive will work as expected, an execution of ngx_http_rewrite_module directives on the server level will be stopped. That means that any other directive from that module (like set, if, return, rewrite etc.), if any, should be placed before the above block. That does not apply to the ngx_http_rewrite_module directives placed at the location level.

There is one more possible caveat. If your https://mydomain.tld/foobar page makes use of any assets (scripts, styles, images etc.), access to those assets should be allowed too. For example, you can change the condition to allow anything started with /foobar prefix using if ($uri ~* ^/foobar) { break; } block. If their addresses cannot be checked with a single regex, you can use several if (...) { break; } blocks.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.