38

i am trying to configure nginx to proxy pass the request to another server, only if the $request_body variable matches on a specific regular expression.

My problem now is, that I don't how to configure this behaviour exactly.

I am currently down to this one:

server {
    listen 80 default;
    server_name test.local;

    location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Host $http_host;

            if ($request_body ~* ^(.*)\.test) {
                    proxy_pass http://www.google.de;
            }

            root /srv/http;
    }

}

but the problem here is, that root has always the upperhand. the proxy won't be passed either way.

any idea on how I could accomplish this?

thanks in advance

6
  • 1
    Are you sure you want to check $request_body against regexp? It will slow your app for x times Also, do you want to do proxy_pass or just redirect ? Commented Oct 24, 2011 at 15:54
  • yeah i have no other choice, unfortunately, and I really need to proxy pass, the application cannot redirect (xml-rpc client) Commented Oct 24, 2011 at 15:56
  • But what's the problem now? Isn't working? What's in logs? Commented Oct 24, 2011 at 16:01
  • yeah it is not working, when i remove the root line, the proxy works, when I add the root line, it's as if the proxy is not configured at all. Commented Oct 24, 2011 at 16:49
  • so I somehow need to manage to make the if working as i would expect it to... Commented Oct 24, 2011 at 16:50

2 Answers 2

22

try this:

server {
    listen 80 default;
    server_name test.local;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $http_host;

        if ($request_body ~* ^(.*)\.test) {
            proxy_pass http://www.google.de;
            break;
        }

        root /srv/http;
    }

}
Sign up to request clarification or add additional context in comments.

4 Comments

thx man, you saved me a lot of time and headache, i'm glad the solution was this simple :D much appreciated!
@sharpner Does this method still work? It doesn't appear to in my testing.
@user973254 did you actually test this? It looks like nginx doesn't read the request_body variable at this point, so it never passes the check...
it does not work anymore. The only thing that's still correct in the answer, is the missing break from the original version. - I "unaccepted" the answer.
19

Nginx routing is based on the location directive which matches on the Request URI. The solution is to temporarily modify this in order to forward the request to different endpoints.

server {
    listen 80 default;
    server_name test.local;

     if ($request_body ~* ^(.*)\.test) {
         rewrite ^(.*)$ /istest/$1;
     }

     location / {
         root /srv/http;
     }

     location /istest/ {
        rewrite ^/istest/(.*)$  $1 break;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass http://www.google.de;

    }
}

The if condition can only safely be used in Nginx with the rewrite module which it is part of. In this example. The rewrite prefixes the Request URI with istest.

The location blocks give precedence to the closest match. Anything matching /istest/ will go to the second block which uses another rewrite to remove /istest/ from the Request URI before forwarding to the upstream proxy.

2 Comments

With this solution, users could also directly access /istest/, circumventing the "if" check. Is there a way to prevent this?
Clients could access the /istest/ path just by including the required string in the request body - so this is not about preventing access to the path. The upstream server should validate the request if it is untrusted. However a hard fail might be enforced with set $my_upstream http://www.google.de; within the condition and proxy_pass $my_upstream; in the location block.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.