Nginx setting for A/B Testing container

Nginx setting for A/B Testing container

The solution is based on browser cookie “ab_test”.

If user first time to access the website, we will randomly dispatch to the backend server, then we set cookie value with the server type(main/test), then for the next request, we will check the cookie value, and dispath it to the previous server.

map $host $MAIN_SERVER { default 127.0.0.2; }
map $host $TEST_SERVER { default 127.0.0.3; }
map $http_user_agent $mobile_agent{
    default 0;
    ~*(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge\s|maemo|midp|mmp|netfront|opera\sm(ob|in)i|palm(\sos)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows\s(ce|phone)|xda|xiino 1;
}

split_clients "app${remote_addr}${http_user_agent}${date_gmt}" $ab_test_token {
        100% "main";
        * "test";
}

map $cookie_ABTest $ABTEST_COOKIE_VALUE {
        default    $ab_test_token;
        "test"     "test";
        "main" "main";
}

map "${ABTEST_COOKIE_VALUE}" $server_host {
        default $MAIN_SERVER;
        "main"  $MAIN_SERVER;
        "test"  $TEST_SERVER;
}

map $https $req_port {
        default 80;
        "on"  443;
}

map $ABTEST_COOKIE_VALUE $cookie_expires {
        default 1;
}

server {
        server_name youservername.here;

        listen 80;
        listen 443 ssl;

        #ssl setting begin
        ssl_certificate     /path/to/cert/file.crt;
        ssl_certificate_key /path/to/cert/file.key;
        ssl_protocols        TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        #ssl setting end;

        #get real ip begin
        set_real_ip_from  172.31.0.0/16;
        set_real_ip_from  127.0.0.1/32;
        real_ip_header    X-Forwarded-For;
        real_ip_recursive on;

        set $real_x_forward_for $HTTP_X_FORWARDED_FOR;
        if ($real_x_forward_for = "" ) {
                set $real_x_forward_for $proxy_add_x_forwarded_for;
        }
        #get real ip end

        # get domain name without "www" begin
        set $domain $host;
        if ($domain ~ "www\.(.*)" ) {
                set $domain $1;
        }
        # get domain name end

        location / {
                proxy_redirect off;
                proxy_cache    off;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $real_x_forward_for;
                proxy_set_header X-Forwarded-Ssl $https;
                add_header       Front-End-Https $https;
                add_header       Set-Cookie "ABTest=${ABTEST_COOKIE_VALUE};Path=/;Max-Age=${cookie_expires};Domain=.${domain};";
                proxy_pass $scheme://$server_host:$server_port;
        }
}
server {
        listen 127.0.0.2:80;
        listen 127.0.0.2:443 ssl;

        #ssl setting begin
        ssl_certificate     /path/to/cert/file.crt;
        ssl_certificate_key /path/to/cert/file.key;
        ssl_protocols        TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        #ssl setting end;

        set_real_ip_from  127.0.0.1/32;
        set_real_ip_from  172.31.0.0/16;
        real_ip_header    X-Forwarded-For;
        real_ip_recursive on;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        location / {
            #limit_req   zone=one  burst=1 nodelay;
        }
}
server {
        listen 127.0.0.3:80;
        listen 127.0.0.3:443 ssl;

        #ssl setting begin
        ssl_certificate     /path/to/cert/file.crt;
        ssl_certificate_key /path/to/cert/file.key;
        ssl_protocols        TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        #ssl setting end;

        set_real_ip_from  127.0.0.1/32;
        set_real_ip_from  172.31.0.0/16;
        real_ip_header    X-Forwarded-For;
        real_ip_recursive on;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        location / {
        limit_req   zone=one  burst=1 nodelay;
        }
}