Skip to content

Commit 56f8119

Browse files
[feat] update reactjs sample guide to use dhi example (#23821)
## Description This PR adds a DHI-based Dockerfile example demonstrating how to build an React.js application using the dhi-node image and serve it through the dhi-nginx image. ## Reviews - [x] Technical review
1 parent d1c7777 commit 56f8119

2 files changed

Lines changed: 100 additions & 10 deletions

File tree

content/guides/reactjs/containerize.md

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ For consistency, please use the same responses shown in the example below when p
7878
| Question | Answer |
7979
|------------------------------------------------------------|-----------------|
8080
| What application platform does your project use? | Node |
81-
| What version of Node do you want to use? | 24.7.0-alpine |
81+
| What version of Node do you want to use? | 24.12.0-alpine |
8282
| Which package manager do you want to use? | npm |
8383
| Do you want to run "npm run build" before starting server? | yes |
8484
| What directory is your build output to? | dist |
@@ -118,13 +118,93 @@ These updates help ensure your app is easy to deploy, fast to load, and producti
118118

119119
### Step 2: Configure the Dockerfile file
120120

121-
Copy and replace the contents of your existing `Dockerfile` with the configuration below:
121+
Before creating a Dockerfile, you need to choose a base image. You can either use the [Node.js Official Image](https://hub.docker.com/_/node) or a Docker Hardened Image (DHI) from the [Hardened Image catalog](https://hub.docker.com/hardened-images/catalog).
122+
123+
Choosing DHI offers the advantage of a production-ready image that is lightweight and secure. For more information, see [Docker Hardened Images](https://docs.docker.com/dhi/).
124+
125+
> [!IMPORTANT]
126+
> This guide uses a stable Node.js LTS image tag that is considered secure when the guide is written. Because new releases and security patches are published regularly, the tag shown here may no longer be the safest option when you follow the guide. Always review the latest available image tags and select a secure, up-to-date version before building or deploying your application.
127+
>
128+
> Official Node.js Docker Images: https://hub.docker.com/_/node
129+
130+
{{< tabs >}}
131+
{{< tab name="Using Docker Hardened Images" >}}
132+
Docker Hardened Images (DHIs) are available for Node.js in the [Docker Hardened Images catalog](https://hub.docker.com/hardened-images/catalog/dhi/node). Docker Hardened Images are freely available to everyone with no subscription required. You can pull and use them like any other Docker image after signing in to the DHI registry. For more information, see the [DHI quickstart](/dhi/get-started/) guide.
133+
134+
1. Sign in to the DHI registry:
135+
```console
136+
$ docker login dhi.io
137+
```
138+
139+
2. Pull the Node.js DHI (check the catalog for available versions):
140+
```console
141+
$ docker pull dhi.io/node:24-alpine3.22-dev
142+
```
143+
144+
3. Pull the Nginx DHI (check the catalog for available versions):
145+
```console
146+
$ docker pull dhi.io/nginx:1.28.0-alpine3.21-dev
147+
```
148+
149+
In the following Dockerfile, the `FROM` instructions use `dhi.io/node:24-alpine3.22-dev` and `dhi.io/nginx:1.28.0-alpine3.21-dev` as the base images.
150+
151+
```dockerfile
152+
# =========================================
153+
# Stage 1: Build the React.js Application
154+
# =========================================
155+
156+
# Use a lightweight Node.js image for building (customizable via ARG)
157+
FROM dhi.io/node:24-alpine3.22-dev AS builder
158+
159+
# Set the working directory inside the container
160+
WORKDIR /app
161+
162+
# Copy package-related files first to leverage Docker's caching mechanism
163+
COPY package.json package-lock.json* ./
164+
165+
# Install project dependencies using npm ci (ensures a clean, reproducible install)
166+
RUN --mount=type=cache,target=/root/.npm npm ci
167+
168+
# Copy the rest of the application source code into the container
169+
COPY . .
170+
171+
# Build the React.js application (outputs to /app/dist)
172+
RUN npm run build
173+
174+
# =========================================
175+
# Stage 2: Prepare Nginx to Serve Static Files
176+
# =========================================
177+
178+
FROM dhi.io/nginx:1.28.0-alpine3.21-dev AS runner
179+
180+
# Copy custom Nginx config
181+
COPY nginx.conf /etc/nginx/nginx.conf
182+
183+
# Copy the static build output from the build stage to Nginx's default HTML serving directory
184+
COPY --chown=nginx:nginx --from=builder /app/dist /usr/share/nginx/html
185+
186+
# Use a non-root user for security best practices
187+
USER nginx
188+
189+
# Expose port 8080 to allow HTTP traffic
190+
# Note: The default NGINX container now listens on port 8080 instead of 80
191+
EXPOSE 8080
192+
193+
# Start Nginx directly with custom config
194+
ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
195+
CMD ["-g", "daemon off;"]
196+
```
197+
198+
{{< /tab >}}
199+
{{< tab name="Using the Docker Official Image" >}}
200+
201+
Now you need to create a production-ready multi-stage Dockerfile. Replace the generated Dockerfile with the following optimized configuration:
122202

123203
```dockerfile
124204
# =========================================
125205
# Stage 1: Build the React.js Application
126206
# =========================================
127-
ARG NODE_VERSION=24.7.0-alpine
207+
ARG NODE_VERSION=24.12.0-alpine
128208
ARG NGINX_VERSION=alpine3.22
129209

130210
# Use a lightweight Node.js image for building (customizable via ARG)
@@ -134,7 +214,7 @@ FROM node:${NODE_VERSION} AS builder
134214
WORKDIR /app
135215

136216
# Copy package-related files first to leverage Docker's caching mechanism
137-
COPY package.json package-lock.json ./
217+
COPY package.json package-lock.json* ./
138218

139219
# Install project dependencies using npm ci (ensures a clean, reproducible install)
140220
RUN --mount=type=cache,target=/root/.npm npm ci
@@ -151,14 +231,14 @@ RUN npm run build
151231

152232
FROM nginxinc/nginx-unprivileged:${NGINX_VERSION} AS runner
153233

154-
# Use a built-in non-root user for security best practices
155-
USER nginx
156-
157234
# Copy custom Nginx config
158235
COPY nginx.conf /etc/nginx/nginx.conf
159236

160237
# Copy the static build output from the build stage to Nginx's default HTML serving directory
161-
COPY --chown=nginx:nginx --from=builder /app/dist /usr/share/nginx/html
238+
COPY --chown=nginx:nginx --from=builder /app/dist /usr/share/nginx/html
239+
240+
# Use a built-in non-root user for security best practices
241+
USER nginx
162242

163243
# Expose port 8080 to allow HTTP traffic
164244
# Note: The default NGINX container now listens on port 8080 instead of 80
@@ -169,6 +249,16 @@ ENTRYPOINT ["nginx", "-c", "/etc/nginx/nginx.conf"]
169249
CMD ["-g", "daemon off;"]
170250
```
171251

252+
> [!NOTE]
253+
> We are using nginx-unprivileged instead of the standard NGINX image to follow security best practices.
254+
> Running as a non-root user in the final image:
255+
>- Reduces the attack surface
256+
>- Aligns with Docker’s recommendations for container hardening
257+
>- Helps comply with stricter security policies in production environments
258+
259+
{{< /tab >}}
260+
{{< /tabs >}}
261+
172262
### Step 3: Configure the .dockerignore file
173263

174264
The `.dockerignore` file tells Docker which files and folders to exclude when building the image.

content/guides/reactjs/develop.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Create a file named `Dockerfile.dev` in your project root with the following con
3636
# =========================================
3737
# Stage 1: Develop the React.js Application
3838
# =========================================
39-
ARG NODE_VERSION=24.7.0-alpine
39+
ARG NODE_VERSION=24.12.0-alpine
4040

4141
# Use a lightweight Node.js image for development
4242
FROM node:${NODE_VERSION} AS dev
@@ -45,7 +45,7 @@ FROM node:${NODE_VERSION} AS dev
4545
WORKDIR /app
4646

4747
# Copy package-related files first to leverage Docker's caching mechanism
48-
COPY package.json package-lock.json ./
48+
COPY package.json package-lock.json* ./
4949

5050
# Install project dependencies
5151
RUN --mount=type=cache,target=/root/.npm npm install

0 commit comments

Comments
 (0)