When securing NGINX servers, we often need to restrict access based on IP ranges. The specific requirement here involves:
- Validating incoming connections against CIDR notation ranges
- Returning custom HTTP status codes (like 444) for blocked requests
- Implementing this at the NGINX configuration level
The most efficient approach uses NGINX's built-in geo
module:
geo $remote_addr $ip_denied {
default 0;
123.123.123.0/24 1;
192.168.1.0/16 1;
# Add more CIDR ranges as needed
}
server {
listen 80;
if ($ip_denied = 0) {
return 444;
}
# Normal server configuration...
}
For more complex scenarios, consider using map
:
map $remote_addr $deny_ip {
default 0;
"123.123.123.0/24" 1;
"192.168.1.0/16" 1;
# Additional ranges
}
server {
if ($deny_ip = 0) {
return 444 "Connection Closed Without Response";
}
}
Important considerations for production environments:
- Test CIDR ranges thoroughly using tools like
ipcalc
- The 444 code (NGINX-specific) immediately closes the connection
- For better performance, place these rules early in configuration
- Combine with
geoip_module
for country-level blocking
For maximum flexibility with OpenResty:
location / {
access_by_lua_block {
local cidr = require "resty.cidr"
if not cidr.ip_in_cidrs(ngx.var.remote_addr, {"123.123.123.0/24"}) then
return ngx.exit(444)
end
}
}
When securing an Nginx web server, you might need to restrict access based on IP ranges. A common requirement is to reject requests from IPs outside specific CIDR blocks with custom HTTP error codes (e.g., 444 for connection closure). Here's how to implement this efficiently.
The geo
module in Nginx is perfect for IP-based conditions. We'll use it to create a variable that flags whether an IP is in our allowed range:
geo $allowed_ip {
default 0;
123.123.123.0/24 1;
}
Combine the geo variable with an if
block in your server configuration:
server {
listen 80;
if ($allowed_ip = 0) {
return 444;
}
# Your regular server configuration
location / {
# Normal processing
}
}
For multiple allowed ranges, extend the geo block:
geo $allowed_ip {
default 0;
123.123.123.0/24 1;
192.168.1.0/24 1;
10.0.0.0/8 1;
}
For large IP ranges, consider:
- Using the
ngx_http_geoip_module
for country-level blocking - Pre-compiling IP lists into binary format with
geoip2
- Implementing rate limiting as an additional layer
Always test with:
nginx -t
service nginx reload
Use tools like curl
or Postman to verify the behavior from both allowed and blocked IPs.