Nginx redirects using Lua
For years, I've been a big fan of DuckDuckGo's bang feature. I use it any time I have a specific site I want to search. For example, if I know the result I want to get is on Wikipedia, you can simply use !w [search term]
rather than having to see a search result page or having to go to Wikipedia and using their search box. You wouldn't think the extra click matters, but it adds up.
However, with DuckDuckGo, if you do not put a !
at the beginning of your search, it will act like any other search engine and show you a page of results.
Google is still the king of getting relevant search results, so I often find myself switching between the two. So much so, I used DuckDuckGoog which provides google search results if you do not use the bang feature but redirects you to DuckDuckGo if you do. I've found it to be the best of both worlds.
Today, DuckDuckGoog is down. It's a fairly straightforward hack to check if your search query starts with a !
, so I decided to host my own. I had never done so in the past because it seemed like such a trivial service to host. It hardly seems worth it to load up a PHP script or redirect to a NodeJS page.
I settled on using NGINX's Lua scripting capabilities. It seemed like the right choice because it gets you as close to the webserver as possible but frees you from the limitations of NGINX's config language. It's available in the nginx-extras package on any debian derived system like Ubuntu or Mint.
You'll need to place this section of config of whatever host you are serving it from.
NGINX configuration
location /search {
include /path/to/duckduckgoog.lua;
}
Here's the script I came up with. It needs to be placed in a file the webserver has access to.
Lua
access_by_lua "
local url = ngx.var.uri
local args = ngx.var.args
function starts(str, start)
return string.sub(str, 1, string.len(start)) == start
end
function split(str, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = '(.-)' .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= '' then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
local q = split(args, '=')[2]
if starts(q, '!') then
local ddg_url = 'https://duckduckgo.com/?q='
-- print(ddg_url .. q)
ngx.redirect(ddg_url .. q, 301)
else
local goog_url = 'https://www.google.com/search?q='
-- print(goog_url .. q)
ngx.redirect(goog_url .. q, 301)
end
";