NGINX.COM
Web Server Load Balancing with NGINX Plus

Administrators of traditional hardware application delivery controllers (ADCs) are often faced with use cases that the rule sets provided by ADC vendors don’t cover, and certainly not at the necessary fine‑grained level of control over how requests and responses are processed. As a result, most organizations have written their own custom rules, and as they move to software‑based load balancers, whether on premises or in the cloud, they need an easy way to migrate that ADC logic along with their applications. NGINX and NGINX Plus offer a powerful configuration language that covers many of these use cases.

This blog post explains how to convert several common types of policies or scripts from popular hardware ADCs to NGINX configuration blocks. We here at NGINX have found that many times the apparent difficulty of converting policies is just due to differences in terminology or implementation and we’d like to bridge that gap.

Editor – For more information about augmenting or replacing hardware ADCs with NGINX Plus, see these resources:

Blog posts

Deployment Guides

Note: Some scripts and policies are indeed too complex to implement easily with the NGINX configuration language, but there are dynamic modules for NGINX and NGINX Plus that enable scripting in Lua, Perl, and JavaScript (with the NGINX JavaScript module in NGINX Plus R10 and later). For more information and use instructions, see Dynamic Modules with NGINX Plus.

The information in this post applies to both NGINX and NGINX Plus, but for brevity we’ll refer to NGINX Plus only in the post.

Migrating Logic for Request Routing

Request routing, also known as content‑based routing or content switching, is a way to host many different applications at the same fully qualified domain name (FQDN) but give the end user the impression of a single unified application. The ADC or NGINX Plus sends each request to the appropriate upstream application based on a header or the URI.

NGINX Plus implements request routing with the location directive, using either a URI prefix or regular expressions to match against requests. For more detail, see the NGINX Plus Admin Guide.

Example 1 – Request Routing Based on URI

In this example, request routing is based on the URI. Specifically, if the URI starts with /music, the request is routed to the music_backend upstream group. All other URIs are sent to the configured default upstream group.

F5 iRule

when HTTP_REQUEST {
    switch -glob [string tolower [HTTP::uri]] {
        "/music*"  {pool music_backend}
        default {pool default_backend}
    }
}

NetScaler Policy

#> add cs vserver csapp HTTP 192.168.10.120 80 -cltTimeout 180
#> add cs policy cs_music -rule "HTTP.REQ.URL.STARTSWITH("/music")"
#> bind cs vserver csapp -policyName cs_music -targetLBVserver music_backend -priority 100
#> bind cs vserver csapp -lbvserver default_backend

NGINX Plus Configuration

location /music {
    proxy_pass http://music_backend;
}
location / {
    proxy_pass http://default_backend;
}

Example 2 – Request Routing Based on the User-Agent Header

The following examples perform request routing based on the User-Agent header in the client request, directing requests from iOS and Android devices to separate backend application servers and traffic from all other devices to a configured application server. In the NGINX Plus map block, the $http_user_agent variable is compared to the specified regular expressions, and the $upstream_choice variable is set to the upstream group associated with the matching expression. Then the $upstream_choice variable determines which upstream group is chosen by the proxy_pass directive.

F5 iRule

when HTTP_REQUEST {
    switch -glob [HTTP::header User-Agent] {
        "*iPhone*"  -
        "*iPad*"  -
        "*iPod*"  {pool iosapp}
        "*Android*"  {pool androidapp}
        default {pool musicapp}
    }
}

NetScaler Policy

#> add cs vserver csapp HTTP 192.168.10.120 80 -cltTimeout 180
#> add cs policy ios_agent -rule "HTTP.REQ.HEADER("User-Agent").CONTAINS("iPhone")
 || HTTP.REQ.HEADER("User-Agent").CONTAINS("iPad") || HTTP.REQ.HEADER("User-Agent").CONTAINS("iPad")"
#> add cs policy android_agent -rule "HTTP.REQ.HEADER("User-Agent").CONTAINS("Android")"
#> bind cs vserver csapp -policyName ios_agent -targetLBVserver ios_backend -priority 100
#> bind cs vserver csapp -policyName android_agent -targetLBVserver android_backend -priority 110
#> bind cs vserver csapp -lbvserver vs_default

NGINX Plus Configuration

map $http_user_agent $upstream_choice {
  ~(iPhone|iPad|iPod) ios_backend;
  ~Android android_backend;
  default default_backend;
}

server {
  listen 80;
  location / {
    proxy_pass http://$upstream_choice;
  }
}

Migrating Logic for Request Redirect

It is often necessary to redirect client requests, for example redirecting a client who sends a plain HTTP request to a connection secured with HTTPS. Other example use cases are shortened URLs or changes in the application URL structure.

To redirect requests with NGINX Plus, use the return directive. It takes two parameters: the response code (for example, 301 or 302) and the redirect URL. For further discussion and more examples, see the NGINX Plus Admin Guide and Creating NGINX Rewrite Rules on our blog.

Example – Request Redirect to HTTPS

The following examples redirect the client from HTTP to HTTPS to ensure the session is encrypted.

F5 iRule

when HTTP_REQUEST {
   HTTP::redirect "https://[getfield [HTTP::host] ":" 1][HTTP::uri]"
}

NetScaler Policy

#> add responder action ssl_redirect_act redirect ""https://" + HTTP.REQ.HEADER("Host").HTTP_HEADER_SAFE + HTTP.REQ.URL.PATH_AND_QUERY.HTTP_URL_SAFE" -responseStatusCode 301
#> add responder policy sslredirect TRUE ssl_redirect_act
#> bind lb vserver default_backend -policyName sslredirect -priority 100 -gotoPriorityExpression END -type REQUEST

NGINX Plus Configuration

location / {
    return 301 https://$host$request_uri;
}

Migrating Logic for Request Rewrite

Common reasons to rewrite requests are to provide additional information in headers or to change the URI, effectively hiding the directory structure of an application or creating URLs that are easier to read and remember.

To manipulate requests with NGINX Plus, use the rewrite directive. It takes two required parameters: a regular expression that matches the string to be rewritten and the replacement string. For further discussion and more examples, see the NGINX Plus Admin Guide and Creating NGINX Rewrite Rules on our blog.

Example – Request Rewrite to Change URI Structure

The following examples rewrite the URI structure of requests for /music/artist/song to /mp3/artistsong.mp3.

F5 iRule

when HTTP_REQUEST {
  if {[string tolower [HTTP::uri]] matches_regex {^/music/([a-z]+)/([a-z]+)/?$} } {
    set myuri [string tolower [HTTP::uri]]
    HTTP::uri [regsub {^/music/([a-z]+)/([a-z]+)/?$} $myuri "/mp3/\1-\2.mp3"]
  }
}

NetScaler Policy

#> add rewrite action act_rewrite_music replace "HTTP.REQ.URL.REGEX_SELECT(re!^\/music\/[a-z]+\/[a-z]+(\/)?$!)" ""/mp3/" + HTTP.REQ.URL.AFTER_REGEX(re!^\/music\/!).BEFORE_REGEX(re!\/[a-z]+(\/)?$!) + "-" + HTTP.REQ.URL.AFTER_REGEX(re!^\/music\/[a-z]+\/!).BEFORE_REGEX(re!(\/)?$!) + ".mp3""
#> add rewrite policy pol_rewrite_music "HTTP.REQ.URL.REGEX_MATCH(re!^\/music\/[a-z]+\/[a-z]+(\/)?$!)" act_rewrite_music
#> bind lb vserver music_backend -policyName pol_rewrite_music -priority 100 -gotoPriorityExpression END -type REQUEST

NGINX Plus Configuration

location ~*^/music/[a-z]+/[a-z]+/?$ {
    rewrite ^/music/([a-z]+)/([a-z]+)/?$ /mp3/$1-$2.mp3 break;
    proxy_pass http://music_backend;
}

Migrating Logic for Response Rewrite

Rewriting the response body is often done along with request routing, to change links in the response body to reflect the new URI structure created by the request routing. It can also be used to make other changes to the response body before it’s sent to the client.

To rewrite HTTP responses with NGINX Plus, use the sub_filter directive. It takes two parameters: the string for NGINX Plus to search for and replace, and the replacement string. For further discussion, see the NGINX Plus Admin Guide.

Example – Response Rewrite to Change Link Paths

The following examples search through the response body for links containing the /mp3/ directory element and replace it with /music/.

F5 iRule

when HTTP_RESPONSE {
   if {[HTTP::header value Content-Type] contains "text"}{
     STREAM::expression {@/mp3/@/music/@}
     STREAM::enable
   }
}

NetScaler Policy

#> add rewrite action act_rewrite_body replace_all "HTTP.RES.BODY(100000)" ""/music/"" -search "text("/mp3/")"
#> add rewrite policy pol_rewrite_body TRUE act_rewrite_body
#> bind lb vserver default_backend -policyName pol_rewrite_body -priority 100 -gotoPriorityExpression END -type RESPONSE

NGINX Plus Configuration

location / {
    sub_filter '/mp3/' '/music/';
    proxy_pass http://default_backend;
}

Conclusion

As you can see, the NGINX and NGINX Plus configuration language covers many scripting use cases associated with ADCs. With this powerful toolset, migrating to software‑based load balancing is simple and straightforward to accomplish.

Use cases that are more complicated, or require custom behavior can be accomplished with embedded scripting languages such as Lua, Perl, and JavaScript (with the NGINX JavaScript module in NGINX Plus R10 and later). For more information and use instructions, see Dynamic Modules.

To try NGINX Plus, start your free 30-day trial today or contact us to discuss your use cases.

Hero image
Cut Costs and Increase Flexibility

See why software load balancers are ideal for your applications



About The Author

Shaun Empie

Shaun Empie

Sr. Sales Engineering Manager

About F5 NGINX

F5, Inc. is the company behind NGINX, the popular open source project. We offer a suite of technologies for developing and delivering modern applications. Together with F5, our combined solution bridges the gap between NetOps and DevOps, with multi-cloud application services that span from code to customer.

Learn more at nginx.com or join the conversation by following @nginx on Twitter.