Next.js (Middleware)
El Middleware de Next.js se ejecuta en el Edge, lo que significa que corre muy cerca de tus usuarios antes de que una solicitud llegue a tus rutas de API, Server Actions o bases de datos. Este es el punto de control óptimo para detener tráfico malicioso.
El Middleware
Esta implementación utiliza el objeto nativo NextRequest para extraer con fiabilidad la IP del cliente. Consulta la API de ProxyTracer utilizando el Edge Runtime y aplica estrictamente un timeout de 500ms para asegurar que tus páginas carguen a máxima velocidad.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
// 1. Extraer la IP (Next.js asigna request.ip de forma segura en Vercel/Edge)
// Recurrir a los encabezados si se aloja en un servidor propio detrás de un proxy inverso personalizado
const ip = request.ip || request.headers.get('x-forwarded-for')?.split(',')[0].trim()
// Permitir el paso si es desarrollo local
if (!ip || ip === '127.0.0.1' || ip === '::1') {
return NextResponse.next()
}
try {
// 2. Consultar la API de ProxyTracer usando fetch nativo con un timeout estricto
const ptResponse = await fetch(`https://api.proxytracer.com/v1/check/${ip}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.PROXYTRACER_API_KEY}`
},
signal: AbortSignal.timeout(500) // Corta la conexión si tarda > 500ms
})
if (ptResponse.ok) {
const data = await ptResponse.json()
// 3. Descartar la conexión inmediatamente si se detecta un proxy/VPN
if (data.proxy === true) {
return NextResponse.json(
{ error: "Access Denied: VPN or Proxy detected." },
{ status: 403 }
)
}
}
} catch (error) {
// Fail open: Si la API agota el tiempo de espera, permitir el tráfico para garantizar la disponibilidad
console.error('ProxyTracer API Error:', error)
}
// 4. El tráfico está limpio, continuar hacia la página o ruta de API solicitada
return NextResponse.next()
}
// 5. Configurar el Matcher
// Aplicar este middleware a rutas sensibles o dejarlo global para proteger todo
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
*/
'/((?!_next/static|_next/image|favicon.ico).*)',
],
}Nota de Despliegue en Vercel: Si haces deploy en Vercel, está garantizado que request.ip sea la IP real del cliente. No necesitas analizar manualmente los encabezados a menos que alojes tu infraestructura Node/Docker en servidores propios.