Heath SchweitzerHeath Schweitzer
← All posts

Cloudflare, Nginx, and Next.js: How My Stack Handles Traffic

April 23, 2026|Heath Schweitzer|4 min read|24 views|Last Updated June 21, 2026

Technology
Diagram showing web requests flowing through Cloudflare, Nginx, and Next.js layers before returning a response.

When a request hits heathschweitzer.com, it passes through three distinct layers before reaching the Next.js application that generates the response. Understanding what each layer does — and why each one is in the stack — makes debugging easier, security better, and performance more predictable.

Layer 1: Cloudflare

Every DNS request for heathschweitzer.com resolves to a Cloudflare IP address, not my server's IP directly. Cloudflare is the outermost layer, and it does several things before traffic ever reaches my infrastructure.

DDoS protection and traffic filtering. Cloudflare absorbs and filters malicious traffic at their network edge — volumetric attacks, bot traffic, scrapers. My origin server only receives traffic that Cloudflare has decided to pass through.

TLS termination at the edge. The HTTPS connection between a visitor's browser and Cloudflare is terminated at Cloudflare's nearest data center. Cloudflare then makes a separate connection to my origin server. This means SSL certificates are managed at two points: Cloudflare's edge cert (which the browser sees) and an origin cert between Cloudflare and my server.

Caching. Static assets — JavaScript bundles, CSS, images — are cached at Cloudflare's edge nodes globally. A visitor in Europe gets these assets from a Cloudflare data center near them rather than from my DigitalOcean server. This dramatically reduces latency for static content without any configuration on my part beyond enabling caching.

DNS management. Cloudflare serves my DNS with sub-millisecond resolution times and provides a clean UI for managing records. Moving DNS to Cloudflare is recommended for just about any small personal site or small business site.

One practical note: Cloudflare's "AI Crawl Control" feature manages its own robots.txt that can conflict with the one in your public/ folder. If you're running Cloudflare and notice robots.txt behaving unexpectedly, that's likely why.

Layer 2: Nginx

Traffic that Cloudflare passes to my origin server hits Nginx first. Nginx is a reverse proxy — it receives HTTP requests and decides what to do with them before the application sees them.

Reverse proxy to Next.js. The core Nginx configuration for a Next.js app is a proxy_pass directive that forwards requests to PM2's Node.js process on port 3001:

location / {
    proxy_pass http://127.0.0.1:3001;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

The X-Real-IP and X-Forwarded-For headers are important — they pass the original client IP to Next.js, since from the application's perspective all requests come from localhost (Nginx). Without these, rate limiting and IP-based logic in the application would see all requests as coming from 127.0.0.1.

Maintenance mode. I added a maintenance block that Nginx checks before proxying. If a flag file exists on disk, Nginx returns a 503 with a static HTML page instead of forwarding the request to Node.js. The deploy script creates this flag before building and removes it after PM2 restarts. Users see a brief maintenance message instead of a 502 error during deploys.

set $maintenance 0;
if (-f /home/heathschweitzer/maintenance.flag) {
    set $maintenance 1;
}
if ($maintenance = 1) {
    return 503;
}
error_page 503 /maintenance.html;
location = /maintenance.html {
    root /home/heathschweitzer/htdocs/heathschweitzer.com/public;
    internal;
}

SSL between Cloudflare and origin. Even though Cloudflare terminates TLS at the edge, the connection between Cloudflare and my server is also HTTPS. CloudPanel manages the origin certificate automatically via Let's Encrypt.

WordPress redirect handling. My old WordPress URLs don't match the new Next.js URL structure. Rather than handling redirects in Next.js (which adds latency), some could be handled at the Nginx level. Currently the redirects live in next.config.ts, which is fine for the volume involved.

Layer 3: Next.js / Node.js

Requests that pass through Cloudflare and Nginx reach the Next.js application running under PM2. This is where the actual work happens — rendering pages, executing API routes, querying the database.

Next.js adds its own internal routing layer. File-based routing maps URL patterns to page components and API handlers. The App Router in Next.js 13+ adds server components, streaming, and layouts on top of this.

Static vs dynamic rendering. Next.js tries to statically generate pages at build time where possible. Pages that depend on runtime data — like the blog index, which shows published posts filtered by current time for scheduled post support — are marked export const dynamic = "force-dynamic" to prevent stale caching.

API routes. The token-gated post API I built lives at /api/v1/posts and is handled by Next.js route handlers. These run in the same Node.js process as the rest of the application, which means they share database connections and environment variables without any additional configuration.

PM2 and process management. Next.js itself is just a Node.js process. PM2 keeps it running, handles restarts on crash, and persists across server reboots. The --update-env flag on restarts ensures new environment variables are picked up.

Why This Layering Makes Sense

Each layer handles what it's best at. Cloudflare handles global distribution, DDoS mitigation, and edge caching — things that are impractical to replicate at the origin level. Nginx handles reverse proxying, maintenance mode, and SSL termination at the server level. Next.js handles application logic, routing, and rendering.

The result is a site that serves static assets from Cloudflare's global network, handles the dynamic application layer from a single well-managed VPS, and has enough operational visibility at each layer to debug problems when they occur.

Tagged

next.jsdevopscloudflarenginx

If this post was useful, consider buying me a coffee ☕ with ₿itcoin — no account needed, any amount welcome.

Bitcoin tip QR code
⚡ Open in Wallet