Docker cookbook · Beginner

Serve a single-page app from a small image

Build a React or Vue app and serve it with correct routing fallback and caching headers.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Build static files in a Node stage, then serve them from nginx with a fallback to index.html for client routes, long caching for hashed assets and no caching for index.html.

Solution

FROM node:24-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:1.29-alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
server {
  listen 80;
  root /usr/share/nginx/html;
  location /assets/ { add_header Cache-Control "public, max-age=31536000, immutable"; }
  location = /index.html { add_header Cache-Control "no-cache"; }
  location / { try_files $uri $uri/ /index.html; }
}

Pitfalls

  • Missing try_files fallback: deep links return 404 on refresh.
  • Caching index.html for a long time, so users keep loading old asset references after deploys.
  • Baking API URLs into the build per environment; read them from a runtime config file instead.

Variations

  • Serve from a CDN or object storage and skip the container entirely.
  • Generate /config.js at container start from environment variables for runtime configuration.

Further reading: Vite: deploying a static site

Reference: https://vite.dev/guide/static-deploy

More Docker recipes

Was this page helpful?