Objective
On rbl.gnoppix.org (~182,000 IPs), we add all IP addresses that attempt to abuse our servers. This is a public RBL initially created for email, but you can also use it for other services, such as web-based applications.
As a modern approach, we use a Gnoppix-trained cybersecurity LLM to analyze traffic patterns. If the AI detects an abuse attempt, the IP address is added to the Gnoppix RBL cluster.
Deploy a secure NGINX setup on Gnoppix 26/27 that filters incoming traffic globally using a custom DNS Real-time Blackhole List (RBL) filter (rbl.gnoppix.org), correctly handles real visitor IP addresses behind Cloudflare, and integrates Redis to track page views and hit counts.
Step 1: Install Required Packages from the Gnoppix repo.
Update your package lists and install NGINX, the official NGINX Lua and Stream modules, Redis, and LuaRocks to manage Lua packages:
sudo apt update
sudo apt install -y nginx libnginx-mod-http-lua libnginx-mod-http-ndk libnginx-mod-stream redis-server luarocks
Verification: Run dpkg -l | grep nginx to confirm all required NGINX modules are installed.
Step 2: Install Lua Dependencies via LuaRocks
Install the necessary OpenResty Lua helper libraries for DNS resolution, Redis connection pooling, and string/caching utilities:
sudo luarocks install lua-resty-redis
sudo luarocks install lua-resty-dns
sudo luarocks install lua-resty-string
sudo luarocks install lua-resty-lrucache
Verification: Run luarocks list to verify that lua-resty-redis and lua-resty-dns are installed.
Step 3: Configure NGINX Modules
Open your primary NGINX configuration file:
sudo nano /etc/nginx/nginx.conf
Ensure the required dynamic modules are loaded at the very top, and define the lua_package_path inside the http {} block so NGINX can find the LuaRocks libraries:
Nginx
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_lua_module.so;
load_module modules/ngx_stream_module.so;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Point to LuaRocks Lua package paths
lua_package_path "/usr/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?.lua;;";
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Verification: Save the file and run sudo nginx -t to ensure the syntax is correct.
Step 4: Configure the Virtual Host with Global RBL and Redis Hit Counter
Open your site-specific configuration file (e.g., /etc/nginx/sites-available/default or your domain configuration):
sudo nano /etc/nginx/sites-available/default
Replace or update the configuration with the complete script below. This places the RBL lookup globally in the server {} block and sets up the Redis counter under /redis:
Nginx
server {
listen 80;
server_name gnoppix.org localhost;
# Global RBL check running on every request across the entire site
access_by_lua_block {
local resolver = require "resty.dns.resolver"
local r, err = resolver:new{
nameservers = {"1.1.1.1", "8.8.8.8"},
retrans = 2,
timeout = 1000
}
if not err then
-- Fallback chain prioritizing Cloudflare's real visitor IP header
local client_ip = ngx.var.http_cf_connecting_ip or ngx.var.http_x_forwarded_for or ngx.var.remote_addr
if client_ip:find(",") then
client_ip = client_ip:match("^%s*(.-)%s*,")
end
local function reverse_ip(ip)
local o1, o2, o3, o4 = ip:match("(%d+)%.(%d+)%.(%d+)%.(%d+)")
if o1 and o2 and o3 and o4 then
return string.format("%s.%s.%s.%s", o4, o3, o2, o1)
end
return nil
end
local reversed = reverse_ip(client_ip)
if reversed then
local rbl_zone = "rbl.gnoppix.org"
local query_domain = reversed .. "." .. rbl_zone
local answers, err = r:query(query_domain, { qtype = r.TYPE_A })
if answers and not answers.errcode then
for _, ans in ipairs(answers) do
if ans.address then
ngx.log(ngx.ERR, "Blocked request from blacklisted IP: ", client_ip, " via ", rbl_zone)
ngx.status = ngx.HTTP_FORBIDDEN
ngx.header.content_type = "text/html; charset=utf-8"
ngx.say([[
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Access Denied - Security Check</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background-color: #0f172a; color: #f8fafc; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
.container { background-color: #1e293b; padding: 2.5rem; border-radius: 12px; box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3); max-width: 450px; width: 100%; border-left: 5px solid #ef4444; }
h1 { font-size: 1.5rem; margin-top: 0; color: #f1f5f9; }
p { color: #94a3b8; line-height: 1.5; font-size: 0.95rem; }
.meta { background: #0f172a; padding: 0.75rem 1rem; border-radius: 6px; font-family: monospace; font-size: 0.85rem; color: #cbd5e1; margin: 1.25rem 0; }
.footer { font-size: 0.8rem; color: #64748b; margin-top: 1.5rem; }
</style>
</head>
<body>
<div class="container">
<h1>Access Denied</h1>
<p>Your request has been blocked by our security perimeter because your IP address matched a threat intelligence list.</p>
<div class="meta">
Client IP: ]] .. client_ip .. [[<br>
Rule: rbl.gnoppix.org
</div>
<p>If you believe this is an error, please reach out to network support.</p>
<div class="footer">Protected by Gnoppix Security Infrastructure</div>
</div>
</body>
</html>
]])
return ngx.exit(ngx.HTTP_FORBIDDEN)
end
end
end
end
end
}
# Location endpoint for testing Redis hit counting
location /redis {
default_type 'text/plain';
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("failed to connect: ", err)
return
end
local res, err = red:incr("hits")
if not err then
ngx.say("Page view count from Redis (Passed Gnoppix RBL): ", res)
else
ngx.say("failed to increment key: ", err)
end
red:set_keepalive(10000, 100)
}
}
}
Step 5: Test and Restart Services
Verify your entire NGINX configuration syntax, then enable and restart NGINX and Redis:
sudo nginx -t
sudo systemctl restart nginx
sudo systemctl enable --now redis-server
Verification: Run curl -i http://localhost/redis to verify that requests increment the Redis hit counter successfully.