npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@edgedev/voidgates-watcher

v1.0.34

Published

Watches access logs and blocks abusive IPs via Cloudflare

Readme

VoidGates Watcher

A lightweight log-monitoring daemon that detects repeated 404 requests from abusive IPs and automatically blocks them via the Cloudflare API — globally or per-zone.

Ideal for protecting Lightsail, Apache, or Nginx servers from brute-force scanners, exploit probes, and bad actors targeting non-existent files.

✨ Features

  • 🛡 Detects excessive 404s from a single IP within a time window
  • 🔒 Automatically blocks the IP via Cloudflare's Access Rules API
  • 📅 Supports automatic unblocking after a configurable duration
  • ♻️ Scheduled cleanup of expired blocks
  • 🌐 Supports global (account-wide) or zone-specific blocking
  • 🧩 Environment-based configuration — easy to customize and deploy
  • 📦 Designed for server environments like Bitnami Lightsail stacks

⚙️ Prerequisites

🟢 Install Node.js and npm (if not already installed)

Use NVM (Node Version Manager) for a clean, user-level install:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

Load it into your current shell:

export NVM_DIR="$HOME/.nvm"
source "$NVM_DIR/nvm.sh"

Then install Node.js (latest LTS):

nvm install --lts

🚀 Installation

npm install -g @edgedev/voidgates-watcher

Or clone for development:

git clone https://github.com/Edge-Marketing-and-Design/voidgates-watcher.git
cd voidgates-watcher
npm install

⚙️ Setup

The first time you run the watcher, it will prompt you to select a location for your config file and fill out all required environment variables. A voidgates.env file will be created for you.

To run the watcher:

npx voidgates-watcher

To rerun the setup process at any time:

npx voidgates-watcher setup

⚠️ If you've installed it globally and your system exposes global binaries, you may also be able to run voidgates-watcher instead of npx voidgates-watcher.


🔧 PM2 Setup (Recommended for Production)

To keep the watcher running continuously and start it on boot:

npm install -g pm2
pm2 start $(which voidgates-watcher) --name voidgates
pm2 startup

👉 Run the command it prints (usually starting with sudo env PATH=...) Then save your process list:

pm2 save

🛠 Example .env Configuration

# Cloudflare API Token must include the following permissions:
# - Scope: Account, Permission: Account Firewall Access Rules, Access Level: Edit
# - Scope: Account, Permission: Account Settings, Access Level: Read
# - Scope: Zone,    Permission: Zone,                      Access Level: Read
# - Scope: Zone,    Permission: Firewall Services,         Access Level: Edit
CF_API_TOKEN=your_cloudflare_token

# Cloudflare Account ID (required for global blocks)
CF_ACCOUNT_ID=your_account_id

# Optional: Cloudflare Zone ID (if set, IPs are blocked only in that zone)
# Leave blank to apply blocks globally (all zones under your account)
VOIDGATES_ZONE=

# Access log path (Apache or Nginx)
LOG_PATH=/opt/bitnami/apache2/logs/access_log

# === 404-Based Blocking Settings ===

# Number of 404s from a single IP before blocking
404_BLOCK_THRESHOLD=10

# Time window (seconds) to trigger threshold
404_BLOCK_INTERVAL_SECONDS=60

# How long (in seconds) the IP should remain blocked
# Leave blank or 0 for permanent block
404_BLOCK_DURATION_SECONDS=3600

# === Path-Based Abuse Blocking Settings ===

# Number of times an IP can hit the same path before being blocked
PATH_BLOCK_THRESHOLD=15

# Time window (in seconds) in which the path threshold must be exceeded
PATH_BLOCK_INTERVAL_SECONDS=60

# How long (in seconds) the IP should remain blocked for path-based blocks
# Leave blank or set to 0 to block permanently
PATH_BLOCK_DURATION_SECONDS=1800

# === Cleanup ===

# How often (in seconds) to check for and remove expired blocks
CLEANUP_INTERVAL_SECONDS=300

# If true, the script will simulate blocks without calling the Cloudflare API
# Useful for testing and development
DRY_RUN=true

🧹 Expired Block Cleanup

A scheduled cleanup function removes expired blocks automatically based on the block duration. Only blocks added by this tool (identified by the note prefix) will be removed.


🔍 Important: Real Visitor IPs

Your server must be configured to trust the CF-Connecting-IP header from Cloudflare to avoid blocking Cloudflare proxy IPs instead of real attackers.

Please follow the official guide to enable real IP support:
https://developers.cloudflare.com/fundamentals/get-started/reference/http-request-headers/#connecting-ip

Apache example:

LoadModule remoteip_module modules/mod_remoteip.so
RemoteIPHeader CF-Connecting-IP

Nginx example:

real_ip_header CF-Connecting-IP;
# Add each Cloudflare IP range
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 104.16.0.0/13;
# ... more ranges ...

🔗 Full list of Cloudflare IP ranges:
https://www.cloudflare.com/ips/


🧪 Testing Locally

Use a mock or sample log file by setting:

LOG_PATH=./test/access_log.txt

Then append test entries like:

192.0.2.123 - - [09/Jul/2025:13:22:00 +0000] "GET /notreal.php HTTP/1.1" 404 512

📄 Notes Format in Cloudflare

Blocked IPs are tagged with a timestamp note for cleanup:

VoidGates 404 Abuse - 2025-07-09T15:32:00Z
VoidGates Path Abuse - 2025-07-09T15:32:00Z

🧑‍💻 License

MIT