Back to Integrations

NGINX Integration

Block or rate-limit requests from ipinsights.io blocklisted IPs in NGINX — no modules required, just core geo and map directives.

Overview

NGINX's geo directive can load a plain IP-list file from disk and expose the result as a variable. We'll generate that file from the ipinsights.io blocklist every hour and use the variable in any server block to return 403, throttle the request, or simply tag it for downstream logging.

Prerequisites

  • NGINX 1.18+ (any flavour — open-source, Plus, OpenResty, Angie)
  • curl available on the host and outbound HTTPS to https://ipinsights.io
  • Permission to write into /etc/nginx/blocklists/ and to reload NGINX

Step 1 — Pull the Blocklist

Write the list out as an NGINX geo-compatible file — one ip 1; entry per line. Save as /usr/local/bin/ipinsights-nginx-sync.sh:

#!/usr/bin/env bash # ipinsights-nginx-sync.sh — generate /etc/nginx/blocklists/ipinsights.conf set -euo pipefail FEED="https://ipinsights.io/downloads/blocklist.txt" DEST=/etc/nginx/blocklists/ipinsights.conf TMP=$(mktemp) trap 'rm -f "$TMP"' EXIT curl -fsSL --max-time 30 "$FEED" \ | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' \ | awk '{ printf "%s 1;\n", $1 }' \ > "$TMP" COUNT=$(wc -l < "$TMP") [ "$COUNT" -ge 100 ] || { echo "refusing — only $COUNT entries"; exit 1; } install -m 0644 -o root -g root "$TMP" "$DEST" nginx -t && systemctl reload nginx

Make it executable and schedule hourly:

sudo install -m 0755 /tmp/ipinsights-nginx-sync.sh /usr/local/bin/ipinsights-nginx-sync.sh sudo mkdir -p /etc/nginx/blocklists echo '0 * * * * root /usr/local/bin/ipinsights-nginx-sync.sh' | sudo tee /etc/cron.d/ipinsights-nginx

Step 2 — Add the geo Block

In nginx.conf inside the http { } context:

http { # ─── IP Insights blocklist ───────────────────────────── geo $ipinsights_block { default 0; include /etc/nginx/blocklists/ipinsights.conf; } # Optional — separate limit_req zone for "suspicious but not blocked" limit_req_zone $binary_remote_addr zone=ipinsights_slow:10m rate=1r/s; # ─────────────────────────────────────────────────────── server { listen 443 ssl; server_name example.com; # Hard-block known-bad IPs if ($ipinsights_block) { return 403; } # …rest of your server config… } }

Prefer rate-limiting? Replace the if with limit_req zone=ipinsights_slow burst=5 nodelay; inside any location after gating on $ipinsights_block.

Step 3 — Optional: Tag the Access Log

Surface the verdict in your access log so dashboards and SIEMs can show it without re-querying:

log_format ipinsights '$remote_addr [$time_local] ' 'ipinsights=$ipinsights_block ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; access_log /var/log/nginx/access.log ipinsights;

Step 4 — Verify

sudo nginx -t && sudo systemctl reload nginx wc -l /etc/nginx/blocklists/ipinsights.conf # Pick a blocklisted IP from https://ipinsights.io/lookup.php and: curl -H "X-Forwarded-For: <blocked-ip>" -I https://example.com/ # if behind a CDN # Otherwise, source the test from a known-bad IP and confirm a 403.

Notes

  • Trust the real client IP: if NGINX sits behind a CDN, set real_ip_header / set_real_ip_from so $remote_addr reflects the actual visitor before the geo block evaluates.
  • CIDR support: geo accepts CIDR notation, so pointing the sync script at /downloads/blocklist-cidr.txt is also valid and reduces the line count significantly.

API Key: Not required for the public blocklist used by this integration.

Request Higher API Limit

Running a high-volume NGINX deployment? If the default rate limit isn't enough for your environment, submit a request below and we'll review it.

Maximum 5,000 characters.