Adding an IP Firewall to Nuxt Without Cloudflare

On self-hosted Nuxt the SecureNow preload works. On Vercel-deployed Nuxt, server middleware + Vercel KV gives you the same outcome.

May 9, 2026·4 min read

Adding an IP Firewall to Nuxt Without Cloudflare

Nuxt 3 deploys in many ways — Node, Vercel, Cloudflare Workers, AWS Lambda. The right firewall approach depends on which runtime your code actually executes in.

Self-hosted Nuxt (Node runtime)

npm install securenow

# In your start command:
node -r securenow/firewall-only .output/server/index.mjs

500k IPs blocked, hourly refresh, automatic crawler allowlisting. The standard recommendation.

For full SecureNow:

node -r securenow/register .output/server/index.mjs

Adds tracing, log capture, and AI investigation.

Vercel-deployed Nuxt

Use server middleware with a Vercel KV-backed dynamic blocklist:

// server/middleware/firewall.ts
import { kv } from '@vercel/kv';

export default defineEventHandler(async (event) => {
  const ip = getRequestHeader(event, 'x-forwarded-for')?.split(',')[0]?.trim()
    || getRequestIP(event)
    || '';

  if (!ip) return;

  const blocked = await kv.sismember('blocklist:ips', ip);
  if (blocked) {
    setResponseStatus(event, 403);
    return 'Forbidden';
  }
});

Refresh the blocklist via a cron job:

// server/api/cron/refresh-blocklist.ts
export default defineEventHandler(async (event) => {
  const auth = getRequestHeader(event, 'authorization');
  if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
    setResponseStatus(event, 401);
    return 'Unauthorized';
  }

  const ips = await fetchSecureNowIpdbBlocklist(); // your fetch logic
  await kv.del('blocklist:ips');
  await kv.sadd('blocklist:ips', ...ips);

  return `Refreshed ${ips.length} IPs`;
});

Schedule in vercel.json:

{
  "crons": [{ "path": "/api/cron/refresh-blocklist", "schedule": "0 * * * *" }]
}

Cloudflare Workers / other edge runtimes

Replace Vercel KV with the runtime-appropriate store:

  • Cloudflare Workers: Workers KV
  • Deno Deploy: Deno KV
  • Other edge platforms: Upstash Redis (HTTP-accessible)

The middleware logic is identical; only the store imports change.

Combining with rate limiting

Layer the rate-limit middleware (see the rate-limiting post) on top. The firewall blocks reputation-based; rate limiting handles per-IP request budgets.

Verifying

For self-host:

npx securenow firewall status

For Vercel KV-backed:

curl -i https://yourapp.com/ -H "X-Forwarded-For: 185.220.101.42"
# Expect: 403 Forbidden if IP is in blocklist

Related

Frequently Asked Questions

Does the SecureNow preload work on Vercel-deployed Nuxt?

No — Vercel runs your Nuxt code on serverless functions where Node preload flags don't apply. Use server middleware with a Vercel KV-backed dynamic blocklist instead.

What about Nitro's built-in deployment targets (Cloudflare Workers, etc.)?

Same logic as Vercel — you can't preload a Node module on edge runtimes. Use server middleware with a runtime-compatible store (Cloudflare KV, Workers KV, or HTTP-accessible Redis like Upstash).

Can I customize the blocklist?

Yes — add per-app rules from the SecureNow dashboard, CLI, or API. Custom rules sync to running SDK instances within ~10 seconds.

Recommended reading

Create Custom Alert Rules From the Command Line

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 11
Secure a Next.js App with SecureNow Using This AI Onboarding Prompt

A 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
nextjs securenow ai onboarding prompt
Adding Backend Tracing to a Sentry Stack with OpenTelemetry

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