Operations 6 min read

How to Implement Gray Release in Nginx Using Cookies, Weights, IP, and Lua

This guide explains multiple Nginx gray‑release techniques—including cookie‑based routing with if and map directives, weight‑based upstream selection, source‑IP routing for separate or shared servers, and a Lua script solution—providing complete configuration snippets and practical tips.

Open Source Tech Hub
Open Source Tech Hub
Open Source Tech Hub
How to Implement Gray Release in Nginx Using Cookies, Weights, IP, and Lua

Cookie‑Based Gray Release

Read the version cookie; if it equals V1 forward to server_01, if V2 forward to server_02, otherwise default to server_01.

1. Using if directive

upstream server_01 {
    server 192.168.1.100:8080 max_fails=1 fail_timeout=60;
}
upstream server_02 {
    server 192.168.1.101:8080 max_fails=1 fail_timeout=60;
}
server {
    listen 80;
    server_name www.server.com;
    set $server "server_01";
    if ($http_cookie ~* "version=V1") { set $server server_01; }
    if ($http_cookie ~* "version=V2") { set $server server_02; }
    location / {
        proxy_pass http://$server;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        index index.html index.htm;
    }
}

2. Using map directive

upstream server_01 { server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }
upstream server_02 { server 192.168.1.101:8080 max_fails=1 fail_timeout=60; }
map $COOKIE_version $server {
    ~*V1$ server_01;
    ~*V2$ server_02;
    default server_01;
}
server {
    listen 80;
    server_name www.server.com;
    location / {
        proxy_pass http://$server;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        index index.html index.htm;
    }
}

Weight‑Based Gray Release

Assign different weights to upstream servers; higher weight receives more traffic.

upstream server {
    server 192.168.1.100:8080 max_fails=1 fail_timeout=60 weight=5;
    server 192.168.1.101:8080 max_fails=1 fail_timeout=60 weight=1;
}
server {
    listen 80;
    server_name www.server.com;
    location / {
        proxy_pass http://server;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        index index.html index.htm;
    }
}

Source‑IP Based Gray Release

1. Resources on different servers

upstream server_01 { server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }
upstream server_02 { server 192.168.1.101:8080 max_fails=1 fail_timeout=60; }
server {
    listen 80;
    server_name www.server.com;
    set $server "server_01";
    if ($remote_addr ~ "211.118.119.11") { set $server server_02; }
    location / {
        proxy_pass http://$server;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        index index.html index.htm;
    }
}

2. Resources on the same server (different document roots)

server {
    listen 80;
    server_name www.server.com;
    set $rootdir "/var/www/html";
    if ($remote_addr ~ "211.118.119.11") { set $rootdir "/var/www/test"; }
    location / {
        root $rootdir;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        index index.html index.htm;
    }
}

Nginx + Lua Gray Release

If the client IP matches an entry in ipList.conf , route to @test_env ; otherwise route to @product_env .

ip_gray.lua script

local ip_config = ngx.shared.config;
local ClientIP = ngx.req.get_headers()["X-Real-IP"]
if ClientIP == nil then
    ClientIP = ngx.req.get_headers()["x_forworded_for"]
end
if ClientIP == nil then
    ClientIP = ngx.var.remote_addr
end
for line in io.lines("/usr/local/nginx/conf/lua/ipList.conf") do
    if not ip_config:get(line) then
        ip_config:set(line, "0")
    end
end
if ip_config:get(ClientIP) == "0" then
    ngx.exec("@test_env")
else
    ngx.exec("@product_env")
end

Lua configuration and locations

lua_code_cache on;
lua_shared_dict config 1m;
upstream MyServer {
    server 192.168.1.199:8099 max_fails=3 fail_timeout=30s;
    server 192.168.1.200:8099 max_fails=3 fail_timeout=30s;
    ip_hash;
}
server {
    listen 80;
    server_name jokerzhang.cn;
    access_log off;
    location / {
        access_by_lua_file /usr/local/nginx/conf/lua/ip_gray.lua;
    }
    location @test_env {
        proxy_pass http://192.168.1.199:8099;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    location @product_env {
        proxy_pass http://MyServer;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

gray releaseNginx
Open Source Tech Hub
Written by

Open Source Tech Hub

Sharing cutting-edge internet technologies and practical AI resources.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.