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
- How to Augment Your F5 Hardware Load Balancer with NGINX
- NGINX Plus vs. Citrix NetScaler: A Price‑Performance Comparison
Deployment Guides
- Migrating Load Balancer Configuration from Citrix ADC to NGINX Plus
- Migrating Load Balancer Configuration from F5 BIG‑IP LTM to NGINX Plus
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/artist‑song.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.