Stop Wasting Monitoring Quota: Block Malicious 404s with NGINX
The Problem
When I first integrated Laravel Nightwatch into my application, the actionable insights were great — until my free monitoring quota started getting wiped out. Why? Malicious bots probing for vulnerable files and endpoints, triggering countless 404s in Laravel:
/wp-login.php
/.env
/server-status
/aws/credentials
My app returned 404s, but Nightwatch still counted them—and so did my logs.
Not Just Me: Inspiration from Michael Dyrynda
I discovered Michael Dyrynda’s blog post, where he tackled the same issue on Laravel Cloud. He used Cloudflare’s WAF for Bot Management to protect critical endpoints with a custom rule by blocking or challenging malicious requests before they ever reached his infrastructure.
What stood out:
- Cloudflare WAF’s Bot Management can block based on bot score or known patterns
- You can also set custom path rules (e.g., blocking /actuator or XML-RPC endpoints)
- This approach works regardless of hosting environment — you just need Cloudflare proxy enabled
When Cloudflare WAF is a Great Option
If you’re using Cloudflare, even on a non-Laravel Cloud setup, their WAF and Bot Management offer powerful, centralized controls:
- Custom firewall rules or managed rulesets to block or challenge bots
- Bot scoring to throttle or drop highly automated traffic
- No changes needed to your origin server — rules are enforced at Cloudflare’s edge
- Even Free/WAF plans include powerful defenses like OWASP rules, Bot Fight Mode, and AI-bot blocking
So yes — Michael’s Cloudflare-based solution is a completely viable and elegant option for many setups. I would encourage this as a way to centralise your bot control.
Why I Chose NGINX Instead
That said, my environment is a self-managed VPS with NGINX, and:
- I didn’t want to rely on Cloudflare — especially for teams not already using it
- I needed something lightweight, portable, and hostname-agnostic
- I wanted to deploy across any server running NGINX without extra services
The result? A simple blocked-routes.conf snippet that stops malicious paths before they reach Laravel or Nightwatch.
🛠 NGINX Blocking Snippet
Grab the full blocklist from my public Gist: View the full config on GitHub Gist
Here’s a preview:
# =====================================================
# NGINX Bot & Exploit Path Blocklist
# Prevents malicious scanners from hitting Laravel
# Returns 444 (no response) to save server + Nightwatch load
# Safe for production — avoids overbroad matches
# =====================================================
# WordPress / common CMS probes
location = /wp-login.php { return 444; }
location = /wp-admin { return 444; }
location = /xmlrpc.php { return 444; }
location ~* ^/wordpress { return 444; }
# Known exploit file paths
location = /.env { return 444; }
location ~* \.(env|bak|old|sql|gz|zip|yml|yaml|json|log|pem|ini|cfg)$ { return 444; }
# Backup & config files by filename (not folders)
location ~* /(backup|config|settings|secrets|credentials|mailer|aws|sendinblue)[\-_]?(prod|dev)?\.(php|js|json|yml|yaml|env|log|sql|gz|zip)$ { return 444; }
# Suspicious tool routes
location = /phpinfo.php { return 444; }
location = /info.php { return 444; }
location = /debug.php { return 444; }
location = /server-status { return 444; }
location = /console.php { return 444; }
# Cloud provider metadata probe attempts
location ~* ^/169\.254\.169\.254 { return 444; }
location ~* ^/latest/meta-data { return 444; }
location ~* ^/metadata/instance { return 444; }
# Dangerous folders with sensitive files
location ~* ^/(admin|dev|test|tmp|private|core|debug|backup|backend|cloudfront|certs|aws_lambda)/.*\.(php|js|json|yml|yaml|env|log|sql|gz|zip)$ { return 444; }
# GraphQL & API gateway probes
location ~* ^/(graphql|swagger|openapi|api-gateway|actuator)/ { return 444; }
# Block sensitive .well-known abuse
location = /.well-known/aws.json { return 444; }
# (Optional) Block all HEAD requests if bots abuse it — test first!
# if ($request_method = HEAD) {
# return 444;
# }
# End of blocklist
Tip: 444 silently drops the connection — perfect for wasting bot cycles
How to Set It Up
- Create the snippet at /etc/nginx/snippets/blocked-routes.conf
- Paste in the rules from the Gist
- Include it in your NGINX config:
include snippets/blocked-routes.conf;
Test and reload:
sudo nginx -t && sudo systemctl reload nginx
Feature | Cloudflare WAF Solution | NGINX Blocklist Solution |
---|---|---|
Requires Cloudflare? | ✅ Yes | ❌ No |
Protects at edge? | ✅ Global via CDN | ✅ Local server-level |
Portability | Moderate (requires Cloudflare setup) | High – usable on any NGINX server |
Customization | Rich WAF & Bot Management UI | Manual editing in configs |
Free-tier viability | WAF/Bot Mode available even free | Requires only NGINX |
Final Thoughts
- If you're already using Cloudflare, leveraging its WAF and Bot Management is easy, powerful, and cloud-agnostic.
- If you don’t want Cloudflare, this NGINX snippet gives you flexibility, control, and portability — with zero dependencies.
A big shout-out to Michael Dyrynda — his Cloudflare-based solution helped inform my implementation and confirmed that proactive edge blocking is the right approach.
Use It Yourself
Grab the NGINX blocklist from my Gist Fork it, tweak it, and reuse it across your infrastructure. Or go the Cloudflare route — whichever fits your stack best.
