DEV Community

Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on • Edited on

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

Hello, I'm Maneshwar. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. Star Us to help devs discover the project. Do give it a try and share your feedback for improving the product.

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

When you're deploying a React app, especially acustom 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

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

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

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

git-lrc
*AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.

git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.*

Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use.

⭐ Star it on GitHub:

GitHub logo HexmosTech / git-lrc

Free, Unlimited AI Code Reviews That Run on Commit




AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs -- without telling you. You often find out in production.

git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.

See It In Action

See git-lrc catch serious security issues such as leaked credentials, expensive cloud operations, and sensitive material in log statements

git-lrc-intro-60s.mp4

Why

  • 🤖 AI agents silently break things. Code removed. Logic changed. Edge cases gone. You won't notice until production.
  • 🔍 Catch it before it ships. AI-powered inline comments show you exactly what changed and what looks wrong.
  • 🔁 Build a

Top comments (0)