react-dockerfile
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Dockerfile Generator
React Dockerfile 生成器
Generate production-ready multi-stage Dockerfiles for React applications served with Nginx.
为搭配Nginx部署的React应用生成可用于生产环境的多阶段Dockerfile。
Workflow
工作流程
- Determine build tool: Vite (default), Create React App, or Next.js static export
- Identify Node.js version from ,
.nvmrcengines, or use Node 22 LTSpackage.json - Check for existing nginx configuration files
- Choose optimization: standard, non-root (recommended), or runtime env vars
Key Insight: Unlike server-side Node.js apps, React apps only need Node.js for building—the runtime is static files served by Nginx. This reduces image size from ~1GB to ~50MB.
- 确定构建工具:Vite(默认)、Create React App(CRA)或Next.js静态导出
- 从、
.nvmrc的engines字段识别Node.js版本,或使用Node 22 LTSpackage.json - 检查是否存在现有的Nginx配置文件
- 选择优化模式:标准模式、非root用户模式(推荐)或运行时环境变量模式
核心要点:与服务端Node.js应用不同,React应用仅在构建阶段需要Node.js——运行时由Nginx提供静态文件服务。这可将镜像大小从约1GB缩减至约50MB。
Image Selection Guide
镜像选择指南
| Scenario | Runtime Image | Compressed Size |
|---|---|---|
| Standard Nginx | | ~45 MB |
| Non-root (recommended) | | ~45 MB |
| With Brotli compression | | ~55 MB |
| 场景 | 运行时镜像 | 压缩后大小 |
|---|---|---|
| 标准Nginx | | ~45 MB |
| 非root用户(推荐) | | ~45 MB |
| 带Brotli压缩 | | ~55 MB |
Standard Pattern
标准模式
dockerfile
undefineddockerfile
undefinedsyntax=docker/dockerfile:1
syntax=docker/dockerfile:1
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
undefinedFROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
undefinedRequired nginx.conf
必需的nginx.conf
Always create with SPA routing, caching, and security headers:
nginx.confnginx
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Hide Nginx version
server_tokens off;
# SPA routing - serve index.html for all routes
location / {
try_files $uri $uri/ /index.html;
}
# Cache hashed assets forever (Vite generates unique hashes)
location ~* \.(?:css|js)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Cache static assets
location ~* \.(?:ico|gif|jpe?g|png|svg|woff2?|ttf|eot)$ {
expires 6M;
add_header Cache-Control "public, max-age=15552000";
}
# No cache for index.html (entry point must always be fresh)
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript
application/xml+rss application/atom+xml image/svg+xml;
# Deny hidden files
location ~ /\. {
deny all;
}
}请务必创建包含SPA路由、缓存和安全头的:
nginx.confnginx
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# 隐藏Nginx版本
server_tokens off;
# SPA路由 - 为所有路由返回index.html
location / {
try_files $uri $uri/ /index.html;
}
# 永久缓存带哈希值的资源(Vite会生成唯一哈希值)
location ~* \.(?:css|js)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# 缓存静态资源
location ~* \.(?:ico|gif|jpe?g|png|svg|woff2?|ttf|eot)$ {
expires 6M;
add_header Cache-Control "public, max-age=15552000";
}
# 不缓存index.html(入口文件必须始终保持最新)
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript
application/xml+rss application/atom+xml image/svg+xml;
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
}Non-Root Pattern (Recommended)
非root用户模式(推荐)
For production security, run Nginx as non-root on port 8080:
dockerfile
undefined为提升生产环境安全性,以非root用户身份在8080端口运行Nginx:
dockerfile
undefinedsyntax=docker/dockerfile:1
syntax=docker/dockerfile:1
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
Create nginx directories with correct permissions
创建拥有正确权限的Nginx目录
RUN mkdir -p /var/run/nginx &&
chown -R nginx:nginx /var/cache/nginx /var/run/nginx &&
chmod -R g+w /var/cache/nginx
chown -R nginx:nginx /var/cache/nginx /var/run/nginx &&
chmod -R g+w /var/cache/nginx
RUN mkdir -p /var/run/nginx &&
chown -R nginx:nginx /var/cache/nginx /var/run/nginx &&
chmod -R g+w /var/cache/nginx
chown -R nginx:nginx /var/cache/nginx /var/run/nginx &&
chmod -R g+w /var/cache/nginx
Copy nginx configs
复制Nginx配置
COPY nginx-main.conf /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY nginx-main.conf /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
Copy static files
复制静态文件
COPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html
USER nginx
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
**Required nginx-main.conf** for non-root operation:
```nginx
worker_processes auto;
pid /var/run/nginx/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}Update nginx.conf to listen on port 8080:
nginx
server {
listen 8080;
# ... rest of config
}COPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html
USER nginx
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
**非root运行必需的nginx-main.conf**:
```nginx
worker_processes auto;
pid /var/run/nginx/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/conf.d/*.conf;
}更新nginx.conf以监听8080端口:
nginx
server {
listen 8080;
# ... 其余配置保持不变
}Build-Time Environment Variables (Vite)
构建时环境变量(Vite)
Vite embeds environment variables at build time. Pass them via build arguments:
dockerfile
undefinedVite会在构建阶段嵌入环境变量。可通过构建参数传递:
dockerfile
undefinedsyntax=docker/dockerfile:1
syntax=docker/dockerfile:1
FROM node:22-alpine AS builder
WORKDIR /app
FROM node:22-alpine AS builder
WORKDIR /app
Accept build arguments
接收构建参数
ARG VITE_API_URL
ARG VITE_APP_TITLE
ARG VITE_API_URL
ARG VITE_APP_TITLE
Make available to Vite build
让Vite构建过程可访问这些变量
ENV VITE_API_URL=$VITE_API_URL
ENV VITE_APP_TITLE=$VITE_APP_TITLE
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Build with:
```bash
docker build \
--build-arg VITE_API_URL=https://api.example.com \
--build-arg VITE_APP_TITLE="My App" \
-t myapp:prod .Important: All Vite environment variables must be prefixed with .
VITE_ENV VITE_API_URL=$VITE_API_URL
ENV VITE_APP_TITLE=$VITE_APP_TITLE
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
构建命令:
```bash
docker build \
--build-arg VITE_API_URL=https://api.example.com \
--build-arg VITE_APP_TITLE="My App" \
-t myapp:prod .重要提示:所有Vite环境变量必须以为前缀。
VITE_Runtime Environment Variables (Advanced)
运行时环境变量(进阶)
For "build once, deploy anywhere" workflows, inject environment variables at container startup:
Step 1: Create :
public/config.js.templatejavascript
window.__ENV__ = {
VITE_API_URL: "__VITE_API_URL__",
VITE_FEATURE_FLAG: "__VITE_FEATURE_FLAG__"
};Step 2: Create :
docker-entrypoint.shbash
#!/bin/sh
set -e针对“一次构建,多环境部署”的工作流,可在容器启动时注入环境变量:
步骤1:创建:
public/config.js.templatejavascript
window.__ENV__ = {
VITE_API_URL: "__VITE_API_URL__",
VITE_FEATURE_FLAG: "__VITE_FEATURE_FLAG__"
};步骤2:创建:
docker-entrypoint.shbash
#!/bin/sh
set -eReplace placeholders with actual environment variables
将占位符替换为实际环境变量
envsubst < /usr/share/nginx/html/config.js.template > /usr/share/nginx/html/config.js
envsubst < /usr/share/nginx/html/config.js.template > /usr/share/nginx/html/config.js
Start nginx
启动Nginx
exec nginx -g "daemon off;"
**Step 3**: Update Dockerfile:
```dockerfile
FROM nginx:stable-alpine AS production
RUN apk add --no-cache gettext
COPY --from=builder /app/dist /usr/share/nginx/html
COPY public/config.js.template /usr/share/nginx/html/config.js.template
COPY docker-entrypoint.sh /docker-entrypoint.sh
COPY nginx.conf /etc/nginx/conf.d/default.conf
RUN chmod +x /docker-entrypoint.sh
EXPOSE 80
ENTRYPOINT ["/docker-entrypoint.sh"]Step 4: Access in React app:
javascript
const apiUrl = window.__ENV__?.VITE_API_URL || import.meta.env.VITE_API_URL;exec nginx -g "daemon off;"
**步骤3**:更新Dockerfile:
```dockerfile
FROM nginx:stable-alpine AS production
RUN apk add --no-cache gettext
COPY --from=builder /app/dist /usr/share/nginx/html
COPY public/config.js.template /usr/share/nginx/html/config.js.template
COPY docker-entrypoint.sh /docker-entrypoint.sh
COPY nginx.conf /etc/nginx/conf.d/default.conf
RUN chmod +x /docker-entrypoint.sh
EXPOSE 80
ENTRYPOINT ["/docker-entrypoint.sh"]步骤4:在React应用中访问变量:
javascript
const apiUrl = window.__ENV__?.VITE_API_URL || import.meta.env.VITE_API_URL;Development Stage
开发阶段
Add a development stage for local dev with hot reload:
dockerfile
undefined添加开发阶段以支持本地开发的热重载:
dockerfile
undefinedsyntax=docker/dockerfile:1
syntax=docker/dockerfile:1
FROM node:22-alpine AS base
WORKDIR /app
COPY package*.json ./
FROM base AS development
RUN npm install
COPY . .
EXPOSE 5173
CMD ["npm", "run", "dev", "--", "--host"]
FROM base AS builder
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Build targets:
```bashFROM node:22-alpine AS base
WORKDIR /app
COPY package*.json ./
FROM base AS development
RUN npm install
COPY . .
EXPOSE 5173
CMD ["npm", "run", "dev", "--", "--host"]
FROM base AS builder
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
构建目标:
```bashDevelopment with hot reload
带热重载的开发环境
docker build --target development -t myapp:dev .
docker run -p 5173:5173 -v $(pwd)/src:/app/src myapp:dev
docker build --target development -t myapp:dev .
docker run -p 5173:5173 -v $(pwd)/src:/app/src myapp:dev
Production
生产环境
docker build --target production -t myapp:prod .
undefineddocker build --target production -t myapp:prod .
undefinedVite Configuration for Docker HMR
用于Docker热模块替换的Vite配置
Configure for hot module replacement in Docker:
vite.config.tstypescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
host: '0.0.0.0', // Listen on all interfaces
port: 5173,
watch: {
usePolling: true, // Required for Docker file watching
},
hmr: {
host: 'localhost',
port: 5173,
},
},
});Note: increases CPU usage but is required for reliable file change detection in Docker.
usePolling: true配置以支持Docker中的热模块替换(HMR):
vite.config.tstypescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
host: '0.0.0.0', // 监听所有网络接口
port: 5173,
watch: {
usePolling: true, // Docker文件监听必需
},
hmr: {
host: 'localhost',
port: 5173,
},
},
});注意:会增加CPU占用,但对Docker中可靠的文件变更检测是必需的。
usePolling: trueMemory Optimization for Large Builds
大型构建的内存优化
Node.js defaults to 512MB memory, which may be insufficient for large Vite builds:
dockerfile
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .Node.js默认内存限制为512MB,对于大型Vite构建可能不足:
dockerfile
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .Increase Node.js memory limit for large builds
为大型构建增加Node.js内存限制
ENV NODE_OPTIONS="--max-old-space-size=4096"
RUN npm run build
undefinedENV NODE_OPTIONS="--max-old-space-size=4096"
RUN npm run build
undefinedCache Optimization
缓存优化
Use BuildKit cache mount for npm packages:
dockerfile
RUN \
npm ci使用BuildKit缓存挂载来缓存npm包:
dockerfile
RUN \
npm ciComplete Production Example
完整生产环境示例
dockerfile
undefineddockerfile
undefinedsyntax=docker/dockerfile:1
syntax=docker/dockerfile:1
ARG NODE_VERSION=22
ARG NODE_VERSION=22
Stage 1: Dependencies
阶段1:安装依赖
FROM node:${NODE_VERSION}-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm
npm ci
npm ci
FROM node:${NODE_VERSION}-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm
npm ci
npm ci
Stage 2: Build
阶段2:构建应用
FROM node:${NODE_VERSION}-alpine AS builder
WORKDIR /app
FROM node:${NODE_VERSION}-alpine AS builder
WORKDIR /app
Build arguments for Vite
Vite构建参数
ARG VITE_API_URL
ARG VITE_APP_VERSION
ENV VITE_API_URL=$VITE_API_URL
ENV VITE_APP_VERSION=$VITE_APP_VERSION
ENV NODE_OPTIONS="--max-old-space-size=4096"
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
ARG VITE_API_URL
ARG VITE_APP_VERSION
ENV VITE_API_URL=$VITE_API_URL
ENV VITE_APP_VERSION=$VITE_APP_VERSION
ENV NODE_OPTIONS="--max-old-space-size=4096"
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
Stage 3: Production
阶段3:生产环境
FROM nginx:stable-alpine AS production
LABEL org.opencontainers.image.source="https://github.com/org/repo"
LABEL org.opencontainers.image.description="Production React application"
FROM nginx:stable-alpine AS production
LABEL org.opencontainers.image.source="https://github.com/org/repo"
LABEL org.opencontainers.image.description="Production React application"
Security: Create non-root setup
安全配置:创建非root用户运行环境
RUN mkdir -p /var/run/nginx &&
chown -R nginx:nginx /var/cache/nginx /var/run/nginx /usr/share/nginx/html &&
chmod -R g+w /var/cache/nginx
chown -R nginx:nginx /var/cache/nginx /var/run/nginx /usr/share/nginx/html &&
chmod -R g+w /var/cache/nginx
RUN mkdir -p /var/run/nginx &&
chown -R nginx:nginx /var/cache/nginx /var/run/nginx /usr/share/nginx/html &&
chmod -R g+w /var/cache/nginx
chown -R nginx:nginx /var/cache/nginx /var/run/nginx /usr/share/nginx/html &&
chmod -R g+w /var/cache/nginx
Copy nginx configs
复制Nginx配置
COPY nginx-main.conf /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY nginx-main.conf /etc/nginx/nginx.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
Copy static files
复制静态文件
COPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html
USER nginx
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
CMD ["nginx", "-g", "daemon off;"]
undefinedCOPY --from=builder --chown=nginx:nginx /app/dist /usr/share/nginx/html
USER nginx
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
CMD ["nginx", "-g", "daemon off;"]
undefinedRequired .dockerignore
必需的.dockerignore
Always create :
.dockerignoredockerignore
node_modules
npm-debug.log*
dist
build
.git
.gitignore
*.md
.env
.env.*
.vscode
.idea
coverage
*.test.*
*.spec.*
__tests__
Dockerfile*
docker-compose*
.dockerignore请务必创建文件:
.dockerignoredockerignore
node_modules
npm-debug.log*
dist
build
.git
.gitignore
*.md
.env
.env.*
.vscode
.idea
coverage
*.test.*
*.spec.*
__tests__
Dockerfile*
docker-compose*
.dockerignoreCreate React App Adjustments
Create React App 适配
For Create React App (CRA) projects:
- Build output is in instead of
build/dist/ - Environment variables use prefix instead of
REACT_APP_VITE_
dockerfile
FROM node:22-alpine AS builder
WORKDIR /app
ARG REACT_APP_API_URL
ENV REACT_APP_API_URL=$REACT_APP_API_URL
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
COPY /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]针对Create React App(CRA)项目:
- 构建输出目录为而非
build/dist/ - 环境变量使用前缀而非
REACT_APP_VITE_
dockerfile
FROM node:22-alpine AS builder
WORKDIR /app
ARG REACT_APP_API_URL
ENV REACT_APP_API_URL=$REACT_APP_API_URL
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine AS production
COPY /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]Verification Checklist
验证检查清单
- Node.js Alpine image for build stage, Nginx Alpine for production
- Include nginx.conf with SPA routing ()
try_files $uri $uri/ /index.html - Copy build output: for Vite,
dist/for CRAbuild/ - Use for non-root execution (listen on 8080)
USER nginx - Cache hashed assets (js/css) with long expiration
- Never cache index.html (entry point must be fresh)
- Include .dockerignore to exclude node_modules
- Consider memory limits for large builds ()
NODE_OPTIONS - Use in Vite config for Docker HMR
usePolling: true
- 构建阶段使用Node.js Alpine镜像,生产阶段使用Nginx Alpine镜像
- 包含带SPA路由的nginx.conf()
try_files $uri $uri/ /index.html - 复制构建输出:Vite项目为,CRA项目为
dist/build/ - 使用以非root用户运行(监听8080端口)
USER nginx - 为带哈希值的资源(js/css)设置长缓存过期时间
- 绝不缓存index.html(入口文件必须保持最新)
- 包含.dockerignore以排除node_modules
- 针对大型构建考虑设置内存限制()
NODE_OPTIONS - 在Vite配置中设置以支持Docker热重载
usePolling: true