ZYVOPMulti-Platform Sync
SeriesAI NewsWhy ZyVOPJoin Discord
LoginGet Started
ZYVOPMulti-Platform Sync

The Developer Publishing Hub. Write once, publish everywhere, and make your work citation-ready with built-in SEO, AEO, and GEO discovery support. Zero reader paywalls.

Content

  • Categories
  • Tags
  • Badges
  • Leaderboard
  • Write Article
  • Newsletter

Company

  • About Us
  • Why ZyVOP
  • Changelog
  • Compare Platforms
  • Hashnode vs ZyVOP
  • DEV vs ZyVOP
  • Developer API & CLI
  • Author Handbook
  • Contact

Connect

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA Policy
  • Code of Conduct

ยฉ 2026 ZyVOP. Developer Publishing Hub.

Zero paywalls ยท Full content ownership
All systems operational
HomeTutorialHow to Hide Your Backend VPS IP Behind Vercel Using Next.js Rewrites
Tutorial

How to Hide Your Backend VPS IP Behind Vercel Using Next.js Rewrites

A step-by-step guide to proxying API requests and securing your backend with custom secret headers.

Pradeep Kumar
Pradeep Kumar
Senior Developer
July 30, 2026Updated August 27, 2026
3 min read
How to Hide Your Backend VPS IP Behind Vercel Using Next.js Rewrites
#backend#Web Development#Proxy#security#VPS#Vercel#NestJS
๐Ÿ‘1

If you host your frontend on Vercel and your backend on a custom VPS, your frontend usually makes API requests directly to the VPS's public IP address or domain. While this works, it exposes your backend server's true IP address to the world, making it vulnerable to direct DDoS attacks, port scanners, and malicious bots.

By using Vercel Rewrites, you can use Vercel's edge network as a shield. To the outside world, your API requests appear to be going to Vercel, while Vercel secretly fetches the data from your VPS behind the scenes.

Here is how you can set up a secure API proxy in Next.js (App Router) and lock down your backend to reject any request that tries to bypass Vercel.

The Architecture

sequenceDiagram
    actor User
    participant Vercel as Vercel (Next.js)
    participant VPS as VPS (NestJS Backend)

    User->>Vercel: Fetch /api-proxy/data
    Note over Vercel: Middleware injects secret header<br/>next.config.ts rewrites path
    Vercel->>VPS: Fetch /data (with Secret Header)
    
    alt Valid Secret
        VPS-->>Vercel: 200 OK (Data)
        Vercel-->>User: 200 OK (Data)
    else Missing/Invalid Secret
        VPS-->>Vercel: 403 Forbidden
    end

    User-xVPS: Direct Request (Blocked 403)

Step 1: Configure Next.js Rewrites

First, we need to tell Next.js to intercept requests made to a specific proxy path (e.g., /api-proxy/*) and forward them to your VPS. We achieve this by adding a rewrite rule to next.config.ts.

To ensure we don't accidentally create proxy loops, we will use a specific environment variable BACKEND_URL solely for the rewrite destination.

// next.config.ts
export default {
  async rewrites() {
    // The true IP of your VPS, safely hidden in Vercel environment variables
    const apiUrl = process.env.BACKEND_URL || 'http://localhost:4000';
    
    return [
      { 
        source: '/api-proxy/:path*', 
        destination: `${apiUrl}/:path*` 
      },
    ];
  },
};

Step 2: Inject a Secret Header at the Edge

Now that the request is proxying through Vercel, we need a way for our backend to know that the request actually came from Vercel. We do this by injecting a secret header.

In Next.js, we can use Edge Middleware to intercept the request and inject the header before the next.config.ts rewrite takes effect.

// middleware.ts (or proxy.ts if you use a custom setup)
import { NextResponse, type NextRequest } from 'next/server';

export function middleware(req: NextRequest) {
  const requestHeaders = new Headers(req.headers);
  const proxySecret = process.env.VERCEL_PROXY_SECRET;

  // Inject the secret key into the headers
  if (proxySecret) {
    requestHeaders.set('x-vercel-proxy-secret', proxySecret);
  }

  // Pass the modified headers along to the Next.js rewrite engine
  return NextResponse.next({
    request: {
      headers: requestHeaders,
    },
  });
}

export const config = {
  matcher: ['/api-proxy/:path*'],
};

Step 3: Lock Down the Backend

If an attacker guesses your VPS IP, they could still bypass Vercel entirely. We need to configure the backend to reject any request that lacks the secret header.

Here is an example of how to enforce this using a global hook in a NestJS + Fastify backend:

// backend/src/main.ts
const fastifyInstance = app.getHttpAdapter().getInstance();

fastifyInstance.addHook('onRequest', (request, reply, done) => {
  const proxySecret = process.env.VERCEL_PROXY_SECRET;
  
  // Exclude localhost (127.0.0.1) so internal Docker health checks still work!
  const isLocal = request.ip === '127.0.0.1' || request.ip === '::1';

  if (proxySecret && !isLocal) {
    const incomingSecret = request.headers['x-vercel-proxy-secret'];
    if (incomingSecret !== proxySecret) {
      reply.status(403).send({ message: 'Forbidden: Invalid proxy secret' });
      return;
    }
  }
  done();
});

[!TIP] Docker Health Checks: Notice the isLocal check. If you use Docker, your container's internal health check pinging localhost won't have the secret header. Bypassing the check for local IPs prevents your deployments from rolling back due to failed health checks!

Step 4: Fixing Server-Side Rendering (SSR/SSG)

There's one hidden "gotcha" with this setup. During the Next.js build process (next build), Next.js generates static pages and makes fetch requests directly to your backend API.

Because these requests originate from the build server and bypass your Next.js middleware, they will fail with a 403 Forbidden error because they lack the x-vercel-proxy-secret header.

To fix this, you must manually inject the secret into your internal API client or Apollo Client configuration:

// lib/apollo-server.ts
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';

const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000';

export const apolloServerClient = new ApolloClient({
  ssrMode: true,
  link: new HttpLink({ 
    uri: `${API_URL}/graphql`, 
    fetch, 
    headers: process.env.VERCEL_PROXY_SECRET 
      ? { 'x-vercel-proxy-secret': process.env.VERCEL_PROXY_SECRET } 
      : {}
  }),
  cache: new InMemoryCache(),
});

Summary

By combining Next.js rewrites, Edge middleware, and a simple backend validation check, you can successfully shield your custom VPS behind Vercel's robust infrastructure. Your true IP address remains a secret, and your API is locked down against direct unauthorized access!

Comments (0)

Login to post a comment.

Pradeep Kumar
Pradeep Kumar

Passionate developer sharing knowledge about modern web technologies and best practices.

Subscribe to Pradeep Kumar's Newsletter

Direct email dispatches when new stories are published. Zero algorithms.

More from Pradeep Kumar

View profile

Mistral Raises โ‚ฌ3B to Make Sovereign, Open-Weight AI the Technology Frontier

Mistral raised โ‚ฌ3 billion in a Series D at a โ‚ฌ21B+ valuation, the largest equity round in European tech history. Here's who's backing it, where the โ‚ฌ3B goes, and what it means if you're building on Mistral's open-weight models today.

7 minSep 8

Sanders and Casar Want to Ban Superintelligent AI โ€” And Freeze Everything Else in the Meantime

Sanders and Casar have introduced a bill to permanently ban superintelligent AI and pause advanced development until a new federal agency sets safety rules โ€” with penalties up to 20 years in prison. It's already drawing pushback from industry and AI safety circles alike.

4 minSep 4

Playa Phone: How a Payphone in the Desert Still Makes Free Calls

A payphone in the middle of Burning Man still makes free calls around the world. Here's how its simple hardware, VoIP connection, and carefully chosen limits keep it working.

7 minSep 1

AnyDoc Architecture Review: Inside Firecrawl's Rust Document-to-Markdown Stack

A technical look at Firecrawl's AnyDoc and pdf-inspector, two open-source Rust libraries designed to turn heterogeneous documents into structured, GitHub-Flavored Markdown while keeping local parsing fast and lightweight.

10 minAug 31

How an AI-Driven Copyright Takedown Got Luanti Pulled From Google Play, Again

Microsoft, acting through AI-driven brand protection vendor Tracer.AI, filed a DMCA notice that temporarily pulled Luanti from Google Play for the second time since 2023. The same company also filed a similar Microsoft-backed claim against the indie voxel game Allumeria earlier this year.

6 minAug 29