Map client header to upstream in nginx
Sometimes you want to route traffic to different endpoints based on a http header.
Avoiding if statements in the nginx config is the most important part here.
The example below is based on the user-agent header that is send from the client.
Test nginx conf to view traffic flow
# create upstreams
# android and other non ios device
upstream android {
server 127.0.0.1:8080;
}
# ios based devices
upstream ios {
server 127.0.0.1:8081;
}
# map to different upstream backends based on user-agent header
map $http_user_agent $mobile_upstream {
default "android";
~iPod "ios";
~iPad "ios";
~iOS "ios";
~iPhone "ios";
}
server {
listen 80;
access_log off;
location / {
proxy_pass http://$mobile_upstream;
}
}
server {
listen 8080;
access_log /var/log/nginx/default-android.log combined;
}
server {
listen 8081;
access_log /var/log/nginx/android-ios.log combined;
}
Another example, when you already have if in your upstream config inside you server{} block
# map function needs to before the server{} block
# I use: /etc/nginx/conf.d/00-map-mobile.conf
# set $mobile_device to 0 or 1
map $http_user_agent $mobile_device {
default 0;
~iPod 1;
~iPad 1;
~iOS 1;
~iPhone 1;
~mobile 1;
~Android 1;
}
# In the server{} block
include /etc/nginx/includes/ab-upstreams.conf
proxy_pass http://$upstream;
# Inside ab-upstreams.conf
# stuur naar nieuwe locatie
if ($http_cookie ~ "version=new") {
set $upstream "new_cluster";
}
if ($request ~ "version=new") {
set $upstream "new_cluster";
}
# stuur user terug naar oude locatie
if ($http_cookie ~ "version=old") {
set $upstream "old_cluster";
}
if ($request ~ "version=old") {
set $upstream "old_cluster";
}
# force modbile naar oude upstreams
if ($mobile_device = 1) {
set $upstream "old_cluster";
}