0
0
Nginxdevops~5 mins

Multi-stage builds for static sites in Nginx - Commands & Configuration

Choose your learning style9 modes available
Introduction
Building static websites often requires preparing files before serving them. Multi-stage builds let you create a small final image by separating the build steps from the serving steps, saving space and improving security.
When you want to compile or build your static site files before serving them with nginx.
When you want to keep your final Docker image small by removing build tools.
When you want to speed up deployment by caching build steps separately.
When you want to separate concerns: build environment vs production environment.
When you want to avoid shipping unnecessary files or dependencies in your final image.
Config File - Dockerfile
Dockerfile
FROM node:18-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:1.25-alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

The first stage uses a lightweight Node.js image to install dependencies and build the static site files into the dist folder.

The second stage uses the official nginx image to serve the built files. It copies only the dist folder from the build stage, keeping the final image small and clean.

The EXPOSE 80 tells Docker the container listens on port 80, and the CMD runs nginx in the foreground.

Commands
Builds the Docker image using the multi-stage Dockerfile. This runs the build stage first, then creates the final nginx image with the built static files.
Terminal
docker build -t my-static-site .
Expected OutputExpected
Sending build context to Docker daemon 10.24MB Step 1/8 : FROM node:18-alpine AS build ---> 3a1f1a2b4c5d Step 2/8 : WORKDIR /app ---> Using cache ---> 7f8e9d0a1b2c Step 3/8 : COPY package.json package-lock.json ./ ---> Using cache ---> 1a2b3c4d5e6f Step 4/8 : RUN npm ci ---> Running in abcdef123456 added 50 packages in 2s Removing intermediate container abcdef123456 ---> 9f8e7d6c5b4a Step 5/8 : COPY . . ---> 123456abcdef Step 6/8 : RUN npm run build ---> Running in fedcba654321 > my-app@1.0.0 build /app > vite build vite v4.3.9 building for production... ✓ 10 modules transformed. dist/index.html dist/assets/index.123abc.js Removing intermediate container fedcba654321 ---> 0a1b2c3d4e5f Step 7/8 : FROM nginx:1.25-alpine ---> 7c8d9e0f1a2b Step 8/8 : COPY --from=build /app/dist /usr/share/nginx/html ---> Using cache ---> 4d3c2b1a0f9e Successfully built 4d3c2b1a0f9e Successfully tagged my-static-site:latest
Runs the built image in a container, mapping port 8080 on your computer to port 80 in the container where nginx serves the site.
Terminal
docker run -d -p 8080:80 --name static-site-container my-static-site
Expected OutputExpected
a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890
-d - Run container in detached mode (in background)
-p 8080:80 - Map host port 8080 to container port 80
--name static-site-container - Assign a name to the container for easy reference
Fetches the homepage from the running container to verify the static site is served correctly.
Terminal
curl http://localhost:8080
Expected OutputExpected
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>My Static Site</title> </head> <body> <h1>Welcome to My Static Site</h1> </body> </html>
Stops and removes the running container to clean up resources after testing.
Terminal
docker stop static-site-container && docker rm static-site-container
Expected OutputExpected
static-site-container static-site-container
Key Concept

If you remember nothing else from this pattern, remember: multi-stage builds let you separate building your static files from serving them, creating smaller and cleaner Docker images.

Common Mistakes
Copying source files directly into the nginx image without building first
Nginx cannot build or process static site files; it only serves files. Without building, the site may not work or be incomplete.
Use a build stage with Node.js or another tool to prepare the static files, then copy only the built files into the nginx image.
Not exposing the correct port or mapping ports incorrectly when running the container
If ports are not mapped, you cannot access the site from your computer's browser.
Use -p 8080:80 to map container port 80 to a host port like 8080.
Running nginx without the 'daemon off;' option in CMD
Nginx will start and immediately exit, causing the container to stop.
Use CMD ["nginx", "-g", "daemon off;"] to keep nginx running in the foreground.
Summary
Use a multi-stage Dockerfile to build static site files in one stage and serve them with nginx in the final stage.
Build the Docker image with 'docker build' to run the build and create a small final image.
Run the container with port mapping to access the site, then verify with curl or a browser.
Stop and remove the container after testing to keep your environment clean.