Sign inSign up

madlabcg/react-nginx

By madlabcg

•Updated 20 days ago

Non-root nginx runtime for React/Vite SPAs with runtime env config. Multi-arch (amd64/arm64).

Image
Web servers
0

178

madlabcg/react-nginx repository overview

⁠react-nginx

Production runtime for React / Vite single-page applications: a non-root nginx (based on nginxinc/nginx-unprivileged) on Alpine Linux, tuned for SPAs.

The image contains no application code and no secrets. Build your app with Node in one stage and copy the output on top of this image.

  • Platforms: linux/amd64, linux/arm64
  • Listens on port 8080 as user nginx (uid 101)
  • Web root: /usr/share/nginx/html

⁠Tags

Tags follow <exact nginx version>-r<revision>:

TagExampleMoves?Use it for
<nginx>-r<n>1.28.2-r1Never (immutable)Production — reproducible builds
<nginx>1.28.2To the latest revision of that nginx versionInspection
<line>1.28To the latest build of the nginx lineEnvironments that want patches automatically
latest—To the latest build of the newest nginx lineQuick tests only

The revision increases when the image is rebuilt without an nginx change and resets to -r1 with every new nginx release.

⁠What's inside

FeatureDetails
SPA routingUnknown paths fall back to index.html (React Router and friends)
Caching/assets/* (Vite hashed output): immutable, 1 year. index.html and routes: no-cache. /env-config.js: no-store
Health/healthz returns 200 and backs the image HEALTHCHECK
SecurityRuns without root, server_tokens off, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, dotfiles denied
Compressiongzip for text, JS, CSS, JSON and SVG
Runtime config/env-config.js generated at startup from PUBLIC_* environment variables

⁠Quick start

# syntax=docker/dockerfile:1
ARG BASE_IMAGE=madlabcg/react-nginx:1.28.2-r1

FROM --platform=$BUILDPLATFORM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM ${BASE_IMAGE}
COPY --from=build --chown=nginx:nginx /app/dist /usr/share/nginx/html
docker run -d -p 8080:8080 -e PUBLIC_API_URL=https://api.example.com my-react-app

⁠Runtime configuration

VITE_* variables are baked into the bundle at build time, so an image built for staging cannot be promoted to production. This image solves that: on startup it writes every PUBLIC_* environment variable to /env-config.js:

window.__ENV__ = {
  "PUBLIC_API_URL": "https://api.example.com",
};

Load it before your bundle and read it with a build-time fallback:

<!-- index.html -->
<script src="/env-config.js"></script>
const runtime = (window as any).__ENV__ ?? {};
export const API_URL: string = runtime.PUBLIC_API_URL ?? import.meta.env.VITE_API_URL;

Never put secrets in PUBLIC_* variables — they are served to every browser.

VariableDefaultDescription
PUBLIC_*—Exposed in window.__ENV__
ENV_CONFIG_PREFIXPUBLIC_Prefix of the variables to expose
ENV_CONFIG_PATH/usr/share/nginx/html/env-config.jsOutput file

All features of the official nginx image entrypoint (templates in /etc/nginx/templates/, NGINX_ENTRYPOINT_QUIET_LOGS, …) keep working.

⁠Customizing

NeedHow
Proxy /api to a backendStart from the bundled config (docker run --rm madlabcg/react-nginx:1.28 cat /etc/nginx/conf.d/default.conf), add a location /api/ { proxy_pass ...; } and COPY nginx.conf /etc/nginx/conf.d/default.conf
App served under a sub-pathSet base in vite.config and adjust try_files in the nginx config
pnpm / yarnIn the build stage: RUN corepack enable, then pnpm install --frozen-lockfile / yarn install --frozen-lockfile
Create React AppCopy /app/build instead of /app/dist

⁠Healthcheck

healthcheck:
  test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/healthz"]
  interval: 30s
  timeout: 5s
  retries: 3

Tag summary

Content type

Image

Digest

sha256:24f57eb0a…

Size

22 MB

Last updated

20 days ago

docker pull madlabcg/react-nginx