cyberwatch-ddos
v1.2.0
Published
ML-powered DDoS detection middleware for Express.js — real-time anomaly detection using Isolation Forest trained on CIC-DDoS2019 dataset
Maintainers
Readme
cyberwatch-ddos
ML-powered DDoS detection middleware for Express.js — protect your Node.js API with real-time anomaly detection powered by an Isolation Forest model trained on the CIC-DDoS2019 dataset.
Normal User → ✅ Express App
Attacker → 🛡️ CyberWatch → 🚫 429 BlockedTable of Contents
- How It Works
- Quick Start (3 Steps)
- Complete Example
- Configuration Reference
- API Methods
- ML Service Setup
- Architecture & Request Flow
- Feature Extraction (18 Features)
- Model Performance
- Deployment Guide
- Troubleshooting
- Contributing
- License
How It Works
CyberWatch consists of two components that work together:
| Component | What it does | Where it runs |
|-----------|-------------|---------------|
| npm package (cyberwatch-ddos) | Express middleware — intercepts requests, extracts traffic features, blocks attackers | Inside your Node.js app |
| ML service (Docker image) | Python FastAPI server — runs the Isolation Forest model, returns anomaly predictions | Docker container (or any server) |
Request flow:
- HTTP request hits your Express app
cyberwatchmiddleware extracts the client IP- Per-IP traffic patterns are tracked (rate, bytes, timing, etc.)
- After enough history (default: 3 requests), 18 network flow features are extracted
- Features are sent to the ML service via
POST /predict - If the model says anomaly with confidence above threshold → 429 Too Many Requests
- Normal traffic flows through to your routes untouched
Key principle: CyberWatch is fail-open — if the ML service is down or slow, all traffic passes through. Your app never breaks.
Quick Start (3 Steps)
Step 1: Start the ML Service (Docker)
docker run -d -p 5000:5000 --name cyberwatch-ml rohitpagi33/cyberwatch-ml:latestVerify it's running:
curl http://localhost:5000/health
# → {"status": "healthy", "model_loaded": true}Don't have Docker? See ML Service Setup for alternatives.
Step 2: Install the npm package
npm install cyberwatch-ddosStep 3: Add to your Express app
const express = require('express');
const { cyberwatch } = require('cyberwatch-ddos');
const app = express();
// Add DDoS protection — that's it!
const guard = cyberwatch({
mlServiceUrl: 'http://localhost:5000',
});
app.use(guard);
// Your routes work exactly as before
app.get('/', (req, res) => res.send('Hello, protected world!'));
// Optional: expose live metrics
app.get('/metrics', (req, res) => res.json(guard.getMetrics()));
app.listen(3000, () => console.log('🛡️ Protected server on :3000'));That's it — 3 steps. Your app now has ML-powered DDoS protection.
Complete Example
This is a full Express API with DDoS protection, metrics endpoints, and manual IP management:
const express = require('express');
const cors = require('cors');
const { cyberwatch } = require('cyberwatch-ddos');
const app = express();
app.use(cors());
app.use(express.json());
// ── Initialize CyberWatch DDoS Guard ────────────────────────
const guard = cyberwatch({
mlServiceUrl: process.env.ML_SERVICE_URL || 'http://localhost:5000',
// Detection tuning (all optional — defaults work well)
anomalyThreshold: 0.5, // block if ML confidence > 50%
blockDuration: 5 * 60 * 1000, // block attackers for 5 minutes
minRequestsBeforeML: 3, // allow first 3 requests from any IP
skipPaths: ['/health'], // don't analyze health-check requests
whitelist: ['127.0.0.1'], // never block these IPs
// Get notified when an attack is blocked
onAnomaly: (ip, score) => {
console.log(`🚨 Blocked — IP: ${ip} | Score: ${score}`);
// Send to your logging/alerting system here
},
debug: false, // set true during development
});
app.use(guard);
// ── Your API routes (completely unchanged) ──────────────────
app.get('/', (req, res) => {
res.json({ message: 'Welcome to My API', protected: true });
});
app.get('/health', (req, res) => {
res.json({ status: 'ok', uptime: process.uptime() });
});
app.get('/api/users', (req, res) => {
res.json([
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
]);
});
// ── DDoS metrics & management endpoints (optional) ──────────
app.get('/api/ddos/metrics', (req, res) => {
res.json(guard.getMetrics());
});
app.get('/api/ddos/blocked', (req, res) => {
const { blockedIPs } = guard.getMetrics();
res.json({ blocked: blockedIPs, total: blockedIPs.length });
});
app.post('/api/ddos/block', (req, res) => {
const { ip } = req.body;
if (!ip) return res.status(400).json({ error: 'ip required' });
guard.blockIP(ip);
res.json({ success: true, message: `Blocked ${ip}` });
});
app.post('/api/ddos/unblock', (req, res) => {
const { ip } = req.body;
if (!ip) return res.status(400).json({ error: 'ip required' });
guard.unblockIP(ip);
res.json({ success: true, message: `Unblocked ${ip}` });
});
// ── Graceful shutdown ───────────────────────────────────────
process.on('SIGTERM', () => guard.destroy());
app.listen(3000, () => console.log('🛡️ Server running on :3000'));Running the example
# Terminal 1: Start ML service
docker run -d -p 5000:5000 --name cyberwatch-ml rohitpagi33/cyberwatch-ml:latest
# Terminal 2: Run your app
npm install cyberwatch-ddos express cors
node server.js
# Terminal 3: Test it
curl http://localhost:3000/ # → normal response
curl http://localhost:3000/api/users # → user list
curl http://localhost:3000/api/ddos/metrics # → live protection statsConfiguration Reference
const guard = cyberwatch(options);All Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| mlServiceUrl | string | 'http://localhost:5000' | URL of the ML inference API |
| mlServiceTimeout | number | 5000 | Timeout for ML requests in milliseconds |
| anomalyThreshold | number | 0.5 | Confidence score (0–1) required to block. Higher = fewer blocks |
| minRequestsBeforeML | number | 3 | Allow this many requests from a new IP before ML kicks in |
| blockDuration | number | 300000 | How long to block a flagged IP in ms (default: 5 min) |
| skipPaths | string[] | ['/health'] | URL paths to skip ML analysis entirely |
| whitelist | string[] | [] | IPs that are never blocked, no matter what |
| onAnomaly | function | null | Callback when an IP is blocked: (ip, score) => {} |
| onRequest | function | null | Callback for every ML-analyzed request: (ip, prediction) => {} |
| debug | boolean | false | Enable verbose console logging |
Configuration Examples
Strict protection (block more aggressively):
cyberwatch({
mlServiceUrl: 'http://localhost:5000',
anomalyThreshold: 0.3, // lower threshold = more blocking
minRequestsBeforeML: 1, // start analyzing immediately
blockDuration: 30 * 60 * 1000, // block for 30 minutes
});Relaxed protection (fewer false positives):
cyberwatch({
mlServiceUrl: 'http://localhost:5000',
anomalyThreshold: 0.8, // only block very obvious attacks
minRequestsBeforeML: 10, // give IPs more time
blockDuration: 60 * 1000, // block for only 1 minute
whitelist: ['10.0.0.0/8'], // trust internal IPs
});Production with logging (alert your team):
cyberwatch({
mlServiceUrl: process.env.ML_SERVICE_URL,
onAnomaly: (ip, score) => {
// Send to Slack, PagerDuty, Datadog, etc.
alertService.send(`DDoS blocked: ${ip} (score: ${score})`);
},
onRequest: (ip, prediction) => {
// Log every prediction for analysis
logger.info({ ip, ...prediction });
},
});API Methods
The cyberwatch() function returns an Express middleware with these extra methods:
const guard = cyberwatch({ mlServiceUrl: 'http://localhost:5000' });
app.use(guard);guard.getMetrics()
Returns real-time protection statistics:
app.get('/api/metrics', (req, res) => res.json(guard.getMetrics()));Response:
{
"uptime": 120000,
"totalRequests": 5423,
"blockedRequests": 342,
"anomalyDetections": 342,
"requestsPerSecond": 45.2,
"blockPercentage": 6.3,
"blockedIPs": [
{
"ip": "45.33.12.1",
"count": 120,
"lastScore": -0.65,
"expiresIn": 180000
}
],
"mlHealthy": true,
"recentAnomalies": [
{
"ip": "45.33.12.1",
"score": -0.65,
"timestamp": "2024-01-15T10:30:00.000Z"
}
]
}guard.blockIP(ip)
Manually block an IP address. Expires after blockDuration.
guard.blockIP('192.168.1.100');guard.unblockIP(ip)
Remove a blocked IP immediately:
guard.unblockIP('192.168.1.100');guard.isBlocked(ip)
Check if an IP is currently blocked:
if (guard.isBlocked('192.168.1.100')) {
console.log('This IP is blocked');
}guard.destroy()
Clean up internal timers. Call this on graceful shutdown:
process.on('SIGTERM', () => {
guard.destroy();
server.close();
});ML Service Setup
The ML service is a lightweight Python FastAPI server (~200MB Docker image) that loads a pre-trained Isolation Forest model.
Option A: Docker Hub (Recommended)
# Pull and run
docker run -d -p 5000:5000 --name cyberwatch-ml rohitpagi33/cyberwatch-ml:latest
# Check health
curl http://localhost:5000/health
# → {"status": "healthy", "model_loaded": true}
# View logs
docker logs cyberwatch-ml
# Stop / Remove
docker stop cyberwatch-ml
docker rm cyberwatch-mlAvailable tags:
| Tag | Description |
|-----|-------------|
| rohitpagi33/cyberwatch-ml:latest | Latest stable release |
| rohitpagi33/cyberwatch-ml:1.0.0 | Pinned version 1.0.0 |
Option B: Docker Compose
Create a docker-compose.yml:
version: '3.8'
services:
ml-service:
image: rohitpagi33/cyberwatch-ml:latest
ports:
- '5000:5000'
restart: unless-stopped
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:5000/health']
interval: 30s
timeout: 10s
retries: 3docker-compose up -dOption C: Build from Source
git clone https://github.com/rohitpagi33/CyberWatch---DDOS-Detection.git
cd CyberWatch---DDOS-Detection/ml-service
# Docker build
docker build -t cyberwatch-ml .
docker run -d -p 5000:5000 cyberwatch-mlOption D: Run with Python directly (no Docker)
git clone https://github.com/rohitpagi33/CyberWatch---DDOS-Detection.git
cd CyberWatch---DDOS-Detection/ml-service
# Create virtual environment
python -m venv venv
# Linux/Mac: source venv/bin/activate
# Windows: .\venv\Scripts\activate
pip install -r requirements.txt
# Train the model (one-time, requires dataset in datasets/ folder)
python train_model.py
# Start the API
python inference_api.py
# → Uvicorn running on http://0.0.0.0:5000ML Service API Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| /health | GET | Returns { status, model_loaded } |
| /predict | POST | Single prediction — accepts 18 features, returns { anomaly, confidence } |
| /batch-predict | POST | Batch predictions — accepts array of feature vectors |
Example: Test a prediction directly
curl -X POST http://localhost:5000/predict \
-H "Content-Type: application/json" \
-d '{"features": [100, 5000, 80, 4000, 1.5, 50, 3000, 0.02, 1, 1, 0, 0, 200, 180, 30, 1500, 25, 1200]}'Response:
{
"anomaly": true,
"confidence": 0.73,
"raw_score": -0.42
}Architecture & Request Flow
┌──────────────────┐ ┌──────────────────────────────┐ ┌──────────────┐
│ │ │ Your Express App │ │ │
│ Client │─────▶│ │─────▶│ Your API │
│ (Browser / │ │ ┌────────────────────────┐ │ │ Routes │
│ API caller) │ │ │ cyberwatch-ddos │ │ │ │
│ │ │ │ middleware │ │ └──────────────┘
└──────────────────┘ │ └──────────┬─────────────┘ │
│ │ │
└─────────────┼─────────────────┘
│
HTTP POST /predict
│
┌─────────────▼─────────────────┐
│ ML Service (Docker) │
│ FastAPI + Isolation Forest │
│ rohitpagi33/cyberwatch-ml │
└───────────────────────────────┘Detailed Request Flow
Request arrives
│
▼
Extract client IP
(X-Forwarded-For, CF-Connecting-IP, req.ip)
│
▼
Is IP whitelisted? ──── YES ──→ next() ──→ Your route
│ NO
▼
Is IP already blocked? ── YES ──→ 429 Too Many Requests
│ NO
▼
Record request metrics (rate, bytes, timing)
│
▼
Has IP sent ≥ minRequestsBeforeML? ── NO ──→ next() ──→ Your route
│ YES
▼
Is path in skipPaths? ── YES ──→ next() ──→ Your route
│ NO
▼
Extract 18 features from IP history
│
▼
Send features to ML service (POST /predict)
│
▼
ML service returns { anomaly, confidence }
│
▼
anomaly=true AND confidence > threshold?
│ YES │ NO
▼ ▼
Block IP next() ──→ Your route
Call onAnomaly()
Return 429Fail-Safe Design
| Scenario | Behavior |
|----------|----------|
| ML service is down | All traffic passes through (fail-open) |
| ML prediction times out | Request allowed through |
| ML returns an error | Request allowed through |
| Middleware throws error | next() called — your app never breaks |
| New IP (< 3 requests) | Always allowed through (building traffic history) |
Feature Extraction (18 Features)
For each IP, the middleware tracks per-request metrics and extracts these network flow features (inspired by CICFlowMeter):
| # | Feature | Description | |---|---------|-------------| | 1 | Fwd Packets/s | Forward (incoming) packet rate | | 2 | Fwd Bytes Total | Total bytes received from client | | 3 | Bwd Packets/s | Backward (outgoing) packet rate | | 4 | Bwd Bytes Total | Total response bytes sent | | 5 | Flow Duration | Time elapsed since first request from this IP | | 6 | Packets/s | Overall request/response rate | | 7 | Bytes/s | Total throughput | | 8 | Flow IAT Mean | Average inter-arrival time between requests | | 9 | Fwd PSH Flags | Keep-alive / persistent connection indicators | | 10 | Bwd PSH Flags | Server push indicators | | 11 | Fwd URG Flags | Urgent priority flags (incoming) | | 12 | Bwd URG Flags | Urgent priority flags (outgoing) | | 13 | Fwd Header Length | Average request header size | | 14 | Bwd Header Length | Average response header size | | 15 | Subflow Fwd Packets | Incoming packets in last 5-second window | | 16 | Subflow Fwd Bytes | Incoming bytes in last 5-second window | | 17 | Subflow Bwd Packets | Outgoing packets in last 5-second window | | 18 | Subflow Bwd Bytes | Outgoing bytes in last 5-second window |
Model Performance
| Metric | Value | |--------|-------| | Algorithm | Isolation Forest (scikit-learn, 200 estimators) | | Dataset | CIC-DDoS2019 (125,170 samples) | | Training | Benign traffic only (46,427 samples — unsupervised) | | Contamination | 0.30 | | Precision | 78.3% | | Recall | 63.7% | | F1-Score | 70.2% |
Attack types detected: SYN Flood, UDP Flood, LDAP Amplification, MSSQL Amplification, NetBIOS Amplification, Portmap, UDP-Lag
For detailed model documentation including training pipeline, feature importance, confusion matrix, and tuning guide, see the ML_DOCUMENTATION.md in the GitHub repository.
Deployment Guide
Production Checklist
// production-config.js
const guard = cyberwatch({
mlServiceUrl: process.env.ML_SERVICE_URL, // never hardcode in prod
anomalyThreshold: 0.5, // tune based on your traffic
blockDuration: 10 * 60 * 1000, // 10 min blocks in prod
skipPaths: ['/health', '/ready', '/metrics'], // skip internal paths
debug: false, // always false in prod
onAnomaly: (ip, score) => {
// 1. Log to your monitoring system
logger.warn({ event: 'ddos_blocked', ip, score });
// 2. Alert your team (Slack, PagerDuty, etc.)
alerting.notify(`DDoS attack blocked: ${ip}`);
},
});Docker Compose (Full Stack)
version: '3.8'
services:
ml-service:
image: rohitpagi33/cyberwatch-ml:latest
ports:
- '5000:5000'
restart: unless-stopped
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:5000/health']
interval: 30s
timeout: 10s
retries: 3
my-api:
build: .
ports:
- '3000:3000'
environment:
- ML_SERVICE_URL=http://ml-service:5000
depends_on:
ml-service:
condition: service_healthy
restart: unless-stoppedCloud Deployment
AWS / GCP / Azure:
- Run the ML service as a container (ECS, Cloud Run, ACI, etc.)
- Set
ML_SERVICE_URLto the internal service URL - Install
cyberwatch-ddosin your Node.js app as usual
Railway / Render / Fly.io:
- Deploy the ML service image
rohitpagi33/cyberwatch-ml:latest - Note the internal URL (e.g.,
http://ml-service.internal:5000) - Set
ML_SERVICE_URLenv var in your Node.js service
Performance
| Metric | Value | |--------|-------| | Added latency | ~50–100ms per request (includes ML roundtrip) | | Throughput | 1,000+ req/s | | Memory | ~50–200MB depending on tracked IPs | | ML inference | <10ms per prediction | | Docker image | ~200MB |
Troubleshooting
| Problem | Solution |
|---------|----------|
| ECONNREFUSED to ML service | Make sure docker run -d -p 5000:5000 rohitpagi33/cyberwatch-ml is running |
| Traffic passes through unblocked | Check debug: true — ML may not be reachable, or threshold may be too high |
| Too many false positives | Increase anomalyThreshold (e.g., 0.7 or 0.8) |
| Legitimate users getting blocked | Add trusted IPs to whitelist or increase minRequestsBeforeML |
| ML health check fails | Run curl http://localhost:5000/health — check Docker logs: docker logs cyberwatch-ml |
| Module not found error | Make sure you installed: npm install cyberwatch-ddos |
| Can't import { cyberwatch } | Use destructuring: const { cyberwatch } = require('cyberwatch-ddos') |
Quick health check script
# Check ML service
curl -s http://localhost:5000/health | python -m json.tool
# Test a prediction
curl -s -X POST http://localhost:5000/predict \
-H "Content-Type: application/json" \
-d '{"features": [1,100,1,100,5,0.4,40,5,0,0,0,0,200,200,1,100,1,100]}' \
| python -m json.toolContributing
Contributions are welcome! See the GitHub repository for source code.
- Fork the repo
- Create a feature branch:
git checkout -b feature/my-feature - Make changes and test
- Submit a pull request
Links
- npm: npmjs.com/package/cyberwatch-ddos
- Docker Hub: hub.docker.com/r/rohitpagi33/cyberwatch-ml
- GitHub: github.com/rohitpagi33/CyberWatch---DDOS-Detection
- ML Documentation: ML_DOCUMENTATION.md
License
MIT — see LICENSE for details.
