Securing Web Services Against Unwanted Traffic with NGINX
Recent studies indicate that a significant portion of internet traffic is generated by bots. According to a 2024 report by Akamai Technologies, bots account for approximately 42% of overall web traffic, with nearly two-thirds being malicious. Similarly, the 2024 Imperva Bad Bot Report highlights that 49.6% of global traffic was bot-generated — a 2% increase from the previous year and the highest level since monitoring began in 2013.
In my own projects, about two-thirds of incoming traffic comes from crawlers — most of them clearly targeting vulnerabilities. While my applications aren't WordPress-based, my logs are full of requests attempting to access WordPress and PHP-related paths. It’s not just noisy — it's a waste of bandwidth and resources.
In this post, I’ll show how to filter unwanted requests at the infrastructure level — specifically using NGINX. But the principle applies to any gateway or ingress controller: security filtering should happen before traffic reaches your application.
Why Not Filter in the App?
I'm a strong believer in moving infrastructure concerns out of the application. As I noted in my earlier post (Optimizing APIs by Offloading Responsibilities to an API Gateway), concerns like rate limiting, CORS, and request filtering are best handled outside the app.
Offloading filtering to NGINX or a gateway improves scalability, security, and maintainability. Plus, I don’t want my apps wasting time responding to traffic they’ll never serve.
What Are We Blocking?
Here are some of the most common malicious or misdirected requests seen in my logs:
/<any>/wp-includes/<any>
/wp-content/<any>
/wp-admin/<any>
<any>.php
<any>.php<any>
/.git/<any>
/.github/
/.env/<any>
/.env.<any>
👉 Pro tip: Check your own logs (access.log
) to find out which unwanted patterns your site attracts.
Practical Example: Denying Unwanted Requests with NGINX
In this example, I’ll use Docker Compose for simplicity.
Step 1: Create security-deny.conf
Place this in your NGINX config directory:
# Deny .git access
location ~* /\.git(/|$) {
deny all;
return 403;
}
# Deny .env access
location ~* /\.env(/|$) {
deny all;
return 403;
}
# Deny wp-content
location ~* /wp-content(.*)+$ {
deny all;
return 403;
}
# Deny wp-admin
location ~* /wp-admin(.*)+$ {
deny all;
return 403;
}
# Deny wp-includes/wlwmanifest and similar
location ~* /wp-includes(.*)+$ {
deny all;
return 403;
}
# Deny suspicious .php file patterns
location ~* \.php[\d\w]+$ {
deny all;
return 403;
}
# Deny all .php files by default
location ~ \.php$ {
deny all;
return 403;
}
**Step 2: Include it in your NGINX `server
server {
listen 80;
server_name yoursite.com;
# Include global deny rules
include /etc/nginx/security-deny.conf;
# Other site-specific configs
}
Step 3: Add to your Docker Compose setup
services:
nginx:
image: nginx:alpine
container_name: nginx-proxy
restart: unless-stopped
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf
- ./nginx/security-deny.conf:/etc/nginx/security-deny.conf
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www/:/var/www/certbot
ports:
- "80:80"
- "443:443"
networks:
- blog-network
Step 4: Restart NGINX
docker compose restart nginx
Final Thoughts
Infrastructure-level filtering is low-effort, high-impact security. By denying malicious and irrelevant requests early, you reduce load on your app servers, lower costs, and harden your attack surface — all with just a few lines of configuration.
🚀 Turbocharge Your Kubernetes Cluster with my Terraform Kits! 🚀
🌟 Slash deployment time and costs! Discover the ultimate solution for efficient, cost-effective Kubernetes Terraform Kits. Perfect for DevOps enthusiasts looking for a reliable, scalable setup.
Learn More about Terraform Kits for AKS,EKS and GKE
No comments are allowed for this post