What:
I want to make requests to a web service from within nginx on each request that goes through nginx and apply some process based on the response I get from the web service.
Application:
I am using nginx as a reverse proxy and have multiple webservices to which traffic is routed to. I want to add an additional webservice (Lets call this AdminService) that would act as admin, this service would handle things like security, billing and other traffic analytics and preprocessing.
For every request the goes through nginx I need to make a request to AdminService, admin service will then analyse the request updating some statistics and the likes and respond with some tags. nginx will then update some headers based on the returned tags and forward the request to the appropriate url.
I've taken a look at the Lua module and it doesn't seem to do webservice call.
I also see that there are Java, Groovy and Clojure modules available, is this perhaps what I should be looking at? Otherwise what should I be looking at?
One option is to use the auth_request module. It's not designed with your scenario in mind and is not a default Nginx module so you need to build from source to compile it in with ./configure --with-http_auth_request_module.
auth_request is used to pre-authenticate Nginx requests via an remote HTTP call. As long as the response header is HTTP 200, then the initial request is processed as normal. This could be used to send the request to your AdminService and the response would be able to determine what happened next.
Something like:
# Default location
location / {
auth_request /AdminService;
# Look for X_UpstreamHost: header in the response
auth_request_set $x_upstreamhost $upstream_http_x_upstreamhost;
# Use the value of the response header to choose the internal processing host
proxy_pass http://$x_upstreamhost;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
# Send requests for AdminService to the AdminService
# This expects AdminService to be listening on a path called AdminService
# and based at ##adminip##
location /AdminService {
proxy_pass http://##adminip##;
}
This will send incoming requests first to the host defined by AdminService. This service must response with a normal 200 header and also x_upstreamhost: #internalHost#. Where #internalHost# is the ip or dn of the host you want to handle the request.
Try it out and if you run into issues, post your server {} block and somebody will take a look.
You can accomplish that using nginx_lua (I like the openresty version) by having a script on the access-by-lua phase to handle your custom processing.
In that script, you could use ngx-location-capture to call your "AdminService" if that webservice is defined as a nginx location; or you could using a http client library (I've used this one) to call external services.
See a similar use case here.