How to Block Bot Traffic in NestJS With No Extra Infra

NestJS guards, interceptors, and global middleware all give you bot-blocking hooks. Here's the cleanest pattern for each.

May 9, 2026·6 min read

How to Block Bot Traffic in NestJS With No Extra Infra

NestJS gives you several places to add bot blocking. The cleanest is global middleware — it runs before guards, before interceptors, and before any handler logic. Here's the production setup.

For broader context see the SecureNow Firewall page.

The simplest setup: SecureNow preload

npm install securenow

# Update your start script:
node -r securenow/firewall-only dist/main.js

This sits below NestJS at the HTTP server level. Bad IPs get blocked before NestJS routes the request. 500k IPs, hourly refresh, automatic Googlebot/GPTBot allowlisting. No NestJS-specific code.

For full SecureNow (firewall + tracing + AI investigation):

node -r securenow/register dist/main.js

The hand-rolled NestJS middleware

If you want middleware-level control inside NestJS:

// src/firewall.middleware.ts
import { Injectable, NestMiddleware, HttpException, HttpStatus } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

const BLOCKED_IPS = new Set([
  '185.220.101.42',
]);

const BAD_UA = /sqlmap|nikto|acunetix|masscan|nmap|python-requests/i;
const GOOD_BOTS = /googlebot|bingbot|gptbot|claudebot|perplexitybot/i;

@Injectable()
export class FirewallMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const ip = (req.headers['x-forwarded-for'] as string)?.split(',')[0]?.trim()
      || req.socket.remoteAddress;
    const ua = req.headers['user-agent'] || '';

    if (GOOD_BOTS.test(ua)) return next();
    if (BLOCKED_IPS.has(ip || '')) throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
    if (BAD_UA.test(ua)) throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);

    next();
  }
}

Wire it globally in your AppModule:

// src/app.module.ts
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { FirewallMiddleware } from './firewall.middleware';

@Module({
  imports: [/* ... */],
  controllers: [/* ... */],
  providers: [/* ... */],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(FirewallMiddleware).forRoutes('*');
  }
}

When to use which

ScenarioApproach
Production NestJS, want maintenance-freeSecureNow preload
Need custom logic + reuse across multiple appsNestJS middleware (above)
Need NestJS Guard semantics (per-route)Custom Guard
Only blocking specific routesApply middleware via forRoutes('login')

With Fastify adapter

If you've switched NestJS to Fastify:

// main.ts
import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter()
  );

  app.getHttpAdapter().getInstance().addHook('onRequest', async (req, reply) => {
    const ip = req.headers['x-forwarded-for']?.toString().split(',')[0]?.trim() || req.ip;
    if (BLOCKED_IPS.has(ip)) {
      reply.status(403).send('Forbidden');
    }
  });

  await app.listen(3000);
}
bootstrap();

Fastify hooks have different ergonomics but achieve the same effect.

Verifying it works

npx securenow firewall status

Or with curl against a known-bad UA:

curl -i https://yourapp.com/ -H "User-Agent: sqlmap/1.5.7"

Related

Frequently Asked Questions

Should I use a Guard, Interceptor, or Middleware?

Middleware for IP blocking (runs first, before guards). Guards for authorization-style checks. Interceptors for response transformation. Bot blocking belongs in middleware.

Does NestJS run on Node runtime?

Always. NestJS apps run on Node, so the SecureNow preload (`-r securenow/firewall-only`) works without modification.

Can I use Express middleware in NestJS?

Yes — NestJS sits on top of Express by default (or Fastify). Express middleware works directly via `app.use()` in main.ts.

What about Fastify-mode NestJS?

If you've configured NestJS with the Fastify adapter, use Fastify hooks instead. The preload still works since both use Node HTTP servers.

Recommended reading

AI Security Auditing, Part 1: Set Up Your AI Agent to Audit Your Code

Part 1 of the AI Security Auditing series. Set up an AI coding agent to audit your application's security locally — install SecureNow, connect your account, and run your first threat-model pass in minutes.

Jul 24
How to Audit Your App's Security With AI: The 2026 Guide

A practical, end-to-end guide to auditing your application's security with an AI coding agent — find vulnerabilities at the code level, build detections at the runtime level, and never upload your codebase to do it.

Jul 24
AI Security Auditing, Part 2: Audit Authentication & Sessions With AI

Part 2 of the AI Security Auditing series. Use an AI agent to audit your login, session, MFA, password-reset and magic-link flows for account-takeover paths — then catch the attempts in live traffic.

Jul 23