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.

Lhoussine
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 fetchAbuseipdbBlocklist(); // 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

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
How to Block Bot Traffic in Express With No Extra Infra

Five approaches to bot blocking in Express, ranked by effort vs. effectiveness. From a 5-line allowlist to a full IP-reputation firewall — all without Cloudflare, AWS WAF, or any new infrastructure.

May 9
How to Block Bot Traffic in Fastify With No Extra Infra

Fastify hooks (onRequest) and the SecureNow preload both work cleanly. Here's the production setup for IP blocking and user-agent filtering.

May 9