DEV Community

Boby Santoso
Boby Santoso

Posted on • Originally published at bybobyy.com

How I Built a Multi-Tenant Static Site Engine with Next.js, Nginx, and Coolify

Over the past few months my Sister started this Embroidery business, and as a good brother I was eager to help her. I really wanted to help her get more visibility online. Naturally, my first thought was: let's make her a simple landing page.

But, here's the thing:

As a Software Engineer who uses coding agents a lot and understands how powerful automation can be, I had zero interest in building landing pages using drag and drop tools. Not with Wix, Wordpress, not with Lovable, not even with V0.
I already pay for Claude Code, and I want the most optimized, scalable, and developer friendly solution I can build.

That’s what led me to this idea:

a Multi-Tenant Static Site Engine with Next.js.

But Boby, Next.js? Static? What are you talking about?

Let me explain.

High-Level Overview

Before diving into the technical details, let me show you what the system looks like from the top.

Most landing pages today are built manually or with drag-and-drop tools.
I wanted something different:

  • Automated
  • Config Driven
  • Super Fast
  • SEO Optimized
  • Super Cheap to Host
  • And able to host hundreds of sites without breaking a sweat

Architecture

This is the “bird's-eye view” of the entire system:

Multi Tenant Landing Page Architecture

  • A single engine built with Next.js
  • A Config Driven system for each tenant
  • A Component Factory that assembles pages
  • A Static Export that generates pure HTML
  • Automated output (sitemap, robots, analytics, Nginx configs)
  • Deployment handled by Coolify, assigning subdomains or custom domains

One engine -> unlimited landing pages.

Build Pipeline

Multi Tenant Landing Page Build Pipeline

Business Config

Each tenant has a JSON config with branding, colors, services, copy, etc.

Component Factory

The engine picks from a library of reusable section templates. For example, you can build commonly used sections like this:

hero
|- default
|- split

features
|- grid
|- list

footer
|- default
|- multi-columns

gallery
|- default
|- scrolling
Enter fullscreen mode Exit fullscreen mode

Static Export (Next.js)

Next.js compiles everything into static HTML.

const nextConfig: NextConfig = {
    output: "export",
    images: {
        unoptimized: true,
    },
    trailingSlash: true,
};
Enter fullscreen mode Exit fullscreen mode

Auto-Generated Assets

The system produces sitemap.xml, robots.txt, analytics, OpenGraph metadata, etc.

Nginx Configuration

The generator builds the routing + subdomain config for each tenant.

Deploy via Coolify

Coolify picks up the output -> reloads Nginx -> site goes live.

What this means in Practice

Instead of building landing pages one by one, I can:

  • onboard a new business
  • fill out a config
  • pick the sections
  • run the generator
  • instantly deploy a fully functional, SEO-ready landing page.

It’s fast, cheap, scalable, and extremely flexible.

Why Static > SSR for This Kind of Project

For a Multi-Tenant system where I want to host tens or hundreds of small business sites, SSR can be overkill:

  • Every request needs a Node.js process to run the app
  • You usually have middleware, auth, data fetching, layout logic on each hit
  • You need to think about concurrency, memory, cold starts, scaling

With static export:

  • Each page is already rendered to HTML at build time
  • Nginx (or any simple web server) just reads files from disk and sends them
  • There's no React/Next.js code running on the server per request
  • No per-request rendering = less CPU, less RAM, less that can break

For my use case (small businesses, mostly “read-only” marketing pages), static wins:

  • First byte is faster (no render step)
  • Less complexity to scale
  • Way easier to reason about performance
  • Much cheaper infrastructure

If I ever need “dynamic” behavior, I can still add:

  • Small API routes, I have one already
  • Client-side interactivity
  • Webhooks or background workers

But the core of the site remains static.

Why I Can Host Hundreds of Pages on a “Cheap” Server

So how much is "cheap"?

A basic cloud server (like a small DigitalOcean/Vultr/Linode instance) typically costs around:

USD $4–7 / month for:

  • 1 vCPU
  • 0.5-1 GB RAM
  • ~10-25 GB SSD
  • 500 GB - 1 TB outbound bandwidth per month

That kind of machine is not great for heavy SSR apps with databases and background jobs.
But for pure static hosting with Nginx, it's actually kind of overpowered.

Rough math:

Let’s say one page (HTML + CSS + a bit of JS) is ~300 KB
With 500 GB outbound bandwidth, you can theoretically serve:

500,000,000 KB / 300 KB ≈ 1.6 million page views per month

With 1 TB bandwidth, that’s ≈ 3.3 million page views per month

Real traffic will be lower, and you'll have images etc. But even if you divide those numbers by 10, you still get hundreds of thousands of page views comfortably.

For a multi-tenant scenario:

100 tenants × 1,000 page views/month each = 100,000 views/month

That’s nothing for a static Nginx box with 500 GB+ bandwidth

And because:

  • There's no SSR
  • No per-tenant backend
  • No database queries per page view

Your main bottleneck becomes bandwidth, not CPU or RAM. And cheap servers already give you a lot of bandwidth for this use case.

So when I say "cheap", I literally mean:

One small cloud instance in the $4–7/month range

If I later outgrow that, I can:

  • Add a CDN in front
  • Scale horizontally (more small boxes)
  • Or move to a slightly bigger instance

But the core benefit stays the same:
Static + Multi-Tenant = a lot of sites on very little infrastructure.

Top comments (0)