Adding an IP Firewall to Next.js Without Cloudflare
On Vercel, Edge middleware blocks at the edge. On self-host, the SecureNow preload blocks at the HTTP server. Both work without DNS changes.
Adding an IP Firewall to Next.js Without Cloudflare
If you don't want to put Cloudflare in front of your Next.js app — for routing reasons, vendor preference, or just simplicity — there are two clean alternatives. Pick based on where your app runs.
For broader context, see the SecureNow Firewall page.
On self-hosted Next.js (Railway, Render, AWS, your own server)
The simplest setup: preload the firewall before Next.js starts.
npm install securenow
# Update your start script:
node -r securenow/firewall-only node_modules/next/dist/bin/next start
Or via NODE_OPTIONS in your Dockerfile / process manager:
NODE_OPTIONS='-r securenow/firewall-only' npm start
Result: every request to your Next.js server passes through an IP check. Blocked IPs get a 403 before Next.js even sees the request. Allowlist for legitimate crawlers (Googlebot, GPTBot, etc.) is automatic.
The Pages Router and App Router are both protected — the firewall sits at the HTTP server level, below the framework.
On Vercel (Edge middleware)
Vercel Edge functions can't use the Node-runtime preload. Use Edge middleware:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { kv } from '@vercel/kv';
const STATIC_BLOCKED = new Set([
'185.220.101.42',
// ... a small static list
]);
const GOOD_BOTS = /googlebot|bingbot|gptbot|claudebot|perplexitybot/i;
export async function middleware(request: NextRequest) {
const ua = request.headers.get('user-agent') || '';
if (GOOD_BOTS.test(ua)) return NextResponse.next();
const ip = request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() || '';
if (STATIC_BLOCKED.has(ip)) {
return new NextResponse('Forbidden', { status: 403 });
}
const dynamicBlock = await kv.sismember('blocklist:ips', ip);
if (dynamicBlock) {
return new NextResponse('Forbidden', { status: 403 });
}
return NextResponse.next();
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};
Populate blocklist:ips from a cron job that pulls a threat-intel feed:
// app/api/cron/refresh-blocklist/route.ts
export async function GET(req: Request) {
// Verify cron secret
const auth = req.headers.get('authorization');
if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response('Unauthorized', { status: 401 });
}
const ips = await fetchSecureNowIpdbBlocklist(); // your fetch logic
await kv.del('blocklist:ips');
await kv.sadd('blocklist:ips', ...ips);
return new Response(`Refreshed ${ips.length} IPs`);
}
Then schedule it in vercel.json:
{
"crons": [{ "path": "/api/cron/refresh-blocklist", "schedule": "0 * * * *" }]
}
That gets you hourly refreshes. Caveats: Vercel KV pricing applies (free tier covers small-to-mid traffic), and you have to maintain the threat feed fetch logic.
On Vercel + SecureNow (hybrid)
For Node-runtime portions of your Next.js app on Vercel (Route Handlers configured for Node, server components on Node), you can run SecureNow there:
// instrumentation.ts
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('securenow/register');
}
}
This gives you the firewall + tracing on Node-runtime requests. Edge-runtime requests fall through to whatever middleware you have. The combination covers both.
Verifying it works
Self-host:
npx securenow firewall status
# Shows blocklist size and last refresh
Vercel Edge:
curl -i https://yourapp.com/api/something -H "X-Forwarded-For: 185.220.101.42"
# Expect: HTTP/1.1 403 Forbidden
Cost comparison
| Approach | Setup time | Maintenance | Monthly cost |
|---|---|---|---|
| Self-host + securenow/firewall-only | 1 minute | 0 | $0 |
| Vercel + Edge middleware (static list) | 30 minutes | low | $0 |
| Vercel + Edge middleware (KV-backed) | 1-2 hours | medium | ~$5–$30 (KV) |
| Vercel + Cloudflare in front | 1-2 hours | low | varies |
For self-hosted Next.js, the SecureNow preload is the obvious choice. For Vercel deployments, the Edge middleware + KV approach works but is more maintenance — Cloudflare in front is sometimes worth the DNS change.
Related
Frequently Asked Questions
Does the SecureNow firewall work on Vercel?
The Node-runtime preload doesn't work on Vercel Edge functions. For Vercel deployments, use Edge middleware for IP blocking and `instrumentation.ts` to enable SecureNow on the Node-runtime portions of your app.
Edge middleware lets you block based on a hard-coded list or one fetched from KV. The SecureNow firewall provides a 500k-IP managed blocklist refreshed hourly with auto-allowlisting for legitimate crawlers. Less work to maintain.
Will this protect API routes only, or pages too?
Both. The HTTP-server-level block applies to every request before Next.js routes it. Edge middleware applies according to your matcher config.
Is there a performance impact?
Sub-millisecond. The IP lookup is in-memory hash + CIDR range scan. For 500k entries, cold start adds ~50MB memory and per-request overhead is negligible.
Recommended reading
SecureNow 8.1 adds `securenow alerts rules create` — define your own detection rules from SQL, scope them to your apps, and ship them without leaving the terminal. Here's how, with a real magic-link brute-force example.
Jun 11A copy-paste prompt that lets an AI coding agent install SecureNow, wire Next.js instrumentation, verify traces and logs, deploy to AWS, simulate attacks, and prove firewall blocking with human approval gates.
May 18
If your team uses Sentry for frontend errors and needs backend distributed tracing without doubling the Sentry bill, here's the OpenTelemetry path that doesn't make you choose.
May 9