DEV Community

Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on

3 2 2 2 2

Serve Static React Files with NGINX in a Multi-Stage Docker Build

Hi there! I'm Maneshwar. Right now, I’m building LiveAPI, a first-of-its-kind tool that helps you automatically index API endpoints across all your repositories. LiveAPI makes it easier to discover, understand, and interact with APIs in large infrastructures.


When you're deploying a React app, especially a custom build (like SSR output or static HTML), you want a clean, production-grade setup to serve those static files efficiently.

Let’s break down how to do this using a multi-stage Docker build and NGINX, with your own customized static output path.

The Setup

We’ll build a React (or in your case, a Solid/Node hybrid) project inside a Docker container, extract only the built static files, and serve them using NGINX.

Your folder contains a custom SSR build that ends up looking something like this:

src/
  ssr/
    index.html
    public/
      styles.css
Enter fullscreen mode Exit fullscreen mode

We want this to be served at http://<host>:3090/signin/.

Multi-Stage Dockerfile

Stage 1: Build the app

# ========== Stage 1: Build ==========
FROM node:18 AS builder

RUN apt-get update && apt-get install -y git

WORKDIR /onelogin

# Copy everything and install deps
COPY . .

RUN npm install && npm run build

# Move the SSR output to /app/signin
RUN mkdir -p /app/signin && \
    cp -r src/ssr/* /app/signin/ && \
    mv /app/signin/public/styles.css /app/signin/styles.css || true && \
    sed -i 's|/public/styles.css|styles.css|g' /app/signin/index.html
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • We clone/build the app and extract only the relevant SSR/static files into /app/signin.
  • A small fix rewrites the CSS path in index.html.

Stage 2: Serve with NGINX

# ========== Stage 2: Serve ==========
FROM nginx:alpine

# Copy the static output
COPY --from=builder /app/signin /usr/share/nginx/html/signin

# Custom NGINX config
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 3090

CMD ["nginx", "-g", "daemon off;"]
Enter fullscreen mode Exit fullscreen mode

nginx.conf

events {}

http {
    include /etc/nginx/mime.types;
    sendfile on;

    server {
        listen 3090;

        location /signin/ {
            alias /usr/share/nginx/html/signin/;
            index index.html;
        }

        location / {
            return 404;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Key points:

  • alias serves files from a specific directory.
  • /signin/ path maps to static SSR files.
  • Everything else returns a 404 (strict routing).

Run & Test

Build the image:

docker build -t react-static-server .
Enter fullscreen mode Exit fullscreen mode

Run the container:

docker run -p 3090:3090 react-static-server
Enter fullscreen mode Exit fullscreen mode

Now open:
👉 http://localhost:3090/signin/

You should see your statically served index.html.

When to Use This

  • Deploying custom SSR builds (e.g. from Vite or Rollup).
  • Serving a lightweight login screen or microfrontend.
  • Isolating parts of your app to different subpaths (/signin, /docs, etc).
  • You don’t need Node.js running in production—just static files.

Bonus: Lock It Down

Want to add Auth headers, cache control, or redirect behavior? Just extend the nginx.conf. For example:

add_header Cache-Control "no-store";
Enter fullscreen mode Exit fullscreen mode

Or basic auth, rate limiting, CORS, etc.

Clean Separation of Concerns

This pattern keeps build logic in Node, and static file serving in NGINX. It results in:

  • Smaller production images
  • Faster cold starts
  • Easier horizontal scaling

LiveAPI helps you get all your backend APIs documented in a few minutes.

With LiveAPI, you can generate interactive API docs that allow users to search and execute endpoints directly from the browser.

LiveAPI Demo

If you're tired of updating Swagger manually or syncing Postman collections, give it a shot.

$150K MiniMax AI Agent Challenge — Build Smarter, Remix Bolder, Win Bigger!

Join the $150k MiniMax AI Agent Challenge — Build your first AI Agent 🤖

Developers, innovators, and AI tinkerers, build your AI Agent and win $150,000 in cash. 💰

Read more →

Top comments (0)

Short-term memory for faster AI agents

Short-term memory for faster AI agents

AI agents struggle with latency and context switching. Redis fixes it with a fast, in-memory layer for short-term context—plus native support for vectors and semi-structured data to keep real-time workflows on track.

Start building

👋 Kindness is contagious

Discover fresh viewpoints in this insightful post, supported by our vibrant DEV Community. Every developer’s experience matters—add your thoughts and help us grow together.

A simple “thank you” can uplift the author and spark new discussions—leave yours below!

On DEV, knowledge-sharing connects us and drives innovation. Found this useful? A quick note of appreciation makes a real impact.

Okay