Building a Custom Edge WAF with
Next.js Middleware and IPASIS
Next.js Middleware allows you to run code before a request completes. This is the perfect place to implement security logic. By filtering traffic at the edge (on Vercel or Cloudflare), you save database resources and compute time.
In this tutorial, we'll build a simple Edge WAF that blocks VPNs from accessing your /signup route.
Prerequisites
You need an IPASIS API Key. You can get a free one here.
The Code
Create or edit your middleware.ts file in the root of your project.
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export async function middleware(request: NextRequest) {
// 1. Only check sensitive routes
if (!request.nextUrl.pathname.startsWith('/signup')) {
return NextResponse.next();
}
// 2. Get the user IP
const ip = request.ip || '1.1.1.1'; // '1.1.1.1' fallback for local dev
try {
// 3. Query IPASIS
const res = await fetch(`https://api.ipasis.com/v1/lookup?ip=${ip}&key=${process.env.IPASIS_KEY}`);
const data = await res.json();
// 4. Block VPNs and Proxies
if (data.is_vpn || data.is_proxy || data.is_tor) {
return new NextResponse(JSON.stringify({ error: 'VPNs not allowed' }), {
status: 403,
headers: { 'Content-Type': 'application/json' }
});
}
} catch (error) {
// Fail open (allow traffic) if API fails to avoid blocking users during outages
console.error('IPASIS lookup failed', error);
}
return NextResponse.next();
}
export const config = {
matcher: '/signup',
};Why "Fail Open"?
In the catch block, we allow the request to proceed. This is called "failing open." It ensures that if the security API has a hiccup, you don't block legitimate users. For critical high-security apps, you might choose to "fail closed" (block everyone), but fail-open is better for user experience.
Performance
IPASIS responds in <20ms globally. Adding this check adds negligible latency to your signup flow but prevents 99% of spam registrations.