Nginx proxy by Request Method

Is it possible/how can I configure an Nginx location block to proxy to different backends depending on the request method (ie. GET/POST)?

The reason is, I am currently handling the 2 methods at 2 different URLs (one via http proxy and the other via fcgi) and am trying to make it more "REST"ful so, would ideally like the GETting the resource to return the list, while POSTing to the same resource should add to the list.


I don't use this configuration, but based on the examples here:

location /service  {
  if ($request_method = POST ) {
    fastcgi_pass 127.0.0.1:1234;
  }

  if ($request_method = GET ) {
     alias /path/to/files;
  }
}

If your writing your own application, you can also consider checking GET/POST in it, and sending X-Accel-Redirect headers to hand off transport of the files to nginx.


Although you could achieve this with if, this is generally discouraged by the Nginx documentation, because if doesn't play well with other directives. For example, assume that GET should be open for everyone, while POST is only for authenticated users, using HTTP Basic Auth. That would require if to be combined with auth_basic, which doesn't work properly.

Here is an alternative that works without if. The trick is to use "GET" and "POST" as part of the upstream names, so these can be addressed by variable substitution:

http {
  upstream other_GET {
    server ...;
  }
  upstream other_POST {
    server ...;
  }
  server {
    location /service {
      proxy_pass http://other_$request_method;
    }
  }
}

To combine this with HTTP Basic Auth for everything but GET, just add a limit_except block:

  ...
    location /service {
      proxy_pass http://other_$request_method;
      limit_except GET {
        auth_basic ...;
      }
    }
  ...

I couldn't get the answer from @timmmmmy to work, but it pointed me to the map documentation and this worked for me:

map $request_method $upstream_location {
   PUT     example.com:8081;
   POST    example.com:8081;
   PATCH   example.com:8081;
   default example.com:8082;
}
server {
   location / {
      proxy_pass https://$upstream_location;
   }
}