Skip to content

Instantly share code, notes, and snippets.

Last active October 20, 2023 10:11
  • Star 78 You must be signed in to star a gist
  • Fork 23 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save danackerson/af7481a869396839b3da to your computer and use it in GitHub Desktop.
using nginx + lua + redis for redirects and rewrites
# using such a setup requires `apt-get install lua-nginx-redis` under Ubuntu Trusty
# more info @
http {
lua_package_path "/etc/nginx/include.d/?.lua;;";
lua_socket_pool_size 100;
lua_socket_connect_timeout 10ms;
lua_socket_read_timeout 10ms;
server {
listen 80;
location / {
include /etc/nginx/include.d/en_US/rewrites/122_lua_st_redis_rewrites.lua;
access_by_lua '
local redis = require "redis"
local red = redis:new()
-- see all available redis: methods @
local ok, err = red:connect("", 6379)
if not ok then
ngx.log(ngx.ERR, "failed to connect to redis: ", err)
return ngx.exit(500)
local redirect_candidate = ngx.var.uri
local args_remainder = ngx.null
local args = ngx.var.args
-- we store internal application rewrites as hash values in Redis for their corresponding pretty URL keys
-- if a bot crawls through asking for /search.action?brand=3210
local hash_rewrite, error = red:hgetall(ngx.var.uri)
--[1]> hgetall /search.action?brand=3210
-- (error) WRONGTYPE Operation against a key holding the wrong kind of value
-- let's find the appropriate redirect URL:
if error then
if args then
local m =, [[^(gclid=.*)?(?<start>.*(shop|brand|tag)=[0-9]+)+&?(.*(shop|sale|searchstring|gender)=.*?&?)*(|&(?<remainder>.*))$]])
if m then
if m["start"] then
redirect_candidate = redirect_candidate .. "?" .. m["start"]
if m["remainder"] then
args_remainder = m["remainder"]
-- and ask Redis for the 301 redirect URL
local rewrite_value, err = red:get(redirect_candidate)
--[1]> get "/search.action?brand=3210"
-- "/Mexx/"
-- create/use a connection pool of size 100 with 0 idle timeout
red:set_keepalive(0, 100)
if rewrite_value ~= ngx.null then
if args_remainder ~= ngx.null then
rewrite_value = rewrite_value .. "?" .. args_remainder
-- and kindly ask the bot to visit /Mexx/ instead
ngx.redirect(rewrite_value, 301);
-- a request for /Sandals/Women/ however
if table.getn(hash_rewrite) > 0 then
red:set_keepalive(0, 100)
-- gives us the following hash from Redis:
--[3]> hgetall /Sandals/Women/
-- 1) "action"
-- 2) "search.action"
-- 3) "params"
-- 4) "gender=women&tag=10580&tag=10630"
-- lets transform to an internal rewrite
arr_rewrite = red:array_to_hash(hash_rewrite)
params = nil
if arr_rewrite["params"] then
params = arr_rewrite["params"]
if args then
if params~=nil then
params = params .. "&" .. args
params = args
if params~=nil then
-- and send off to our app server for processing
ngx.req.set_uri("/" .. arr_rewrite["action"])
Copy link

roguh commented Jul 27, 2023

Note that this requires the Nginx Lua module, so Nginx must be compiled with it or it must dynamically load the Lua module. I've used the fabiocicerchia/nginx-lua Docker image, as well as Kubernetes' ingress-nginx.

I'd recommend using access_by_lua_file instead of access_by_lua so you can store the Lua script in its own pure-Lua file. This helps with syntax highlighting and any code quality tools you might use.

Copy link

very valid points @roguh!

for context (since timestamps are a bit obfuscated on gists), I wrote/used this script back in 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment