① 创建 Swap(必须,否则大概率 OOM)
sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
sudo sysctl vm.swappiness=10
② 修改 Dockerfile — 限制内存 + 简化构建
Edit apps/web/Dockerfile
# 1. 必须从 monorepo 根目录构建
# 2. 使用 turbo prune 提取最小依赖集
# 3. 使用 --frozen-lockfile 确保构建可重复性
# 4. 支持 Next.js 构建时环境变量注入
# 5. 低配服务器优化:限制内存、减少并发
# ============================================
FROM node:22-slim AS base
RUN corepack enable
# 全局限制 Node.js 内存,防止 OOM
ENV NODE_OPTIONS="--max-old-space-size=512"
# ============================================
# 阶段 1: 使用 turbo prune 提取依赖
# ============================================
FROM base AS pruner
...
# 再复制 prune 的完整源代码(会覆盖上面的源文件,但保留 node_modules)
COPY --from=pruner /app/out/full/ ./
# 构建应用(使用 turbo 在根目录构建)
# Next.js 会生成 standalone 输出到 apps/web/.next
RUN pnpm turbo build --filter=nodebbs-web
# 构建应用 — 限制并发,避免内存峰值
# CONCURRENT_TASKS=1 确保同一时间只编译一个任务
RUN CONCURRENT_TASKS=1 pnpm turbo build --filter=nodebbs-web --concurrency=1
# ============================================
# 阶段 4: 生产环境运行时(仅包含运行时文件)
# ============================================
③ 优化 next.config.mjs — 减少编译量
hostname: "**",
},
],
},
// 启用 standalone 输出模式,用于 Docker 部署
output: 'standalone',
// 代理逻辑已迁移至 src/proxy.js,以支持 Docker 运行时环境变量动态注入
// 增加中间件请求体大小限制,支持大文件上传
experimental: {
proxyClientMaxBodySize: '100mb',
// Next.js 默认已优化 lucide-react / date-fns 等,这里补齐项目在用但不在默认列表的 barrel 包
optimizePackageImports: [
'framer-motion',
'@dnd-kit/core',
'@dnd-kit/sortable',
'@radix-ui/react-icons',
'react-syntax-highlighter',
'lucide-react',
'date-fns',
'dayjs',
],
}
},
webpack: (config, { isServer }) => {
if (isServer) {
// 限制编译进程数,降低内存峰值
config.optimization = config.optimization || {};
config.optimization.splitChunks = false;
}
return config;
},
};
export default nextConfig;
Edit apps/web/next.config.mjs
'dayjs',
],
},
webpack: (config, { isServer }) => {
if (isServer) {
// 限制编译进程数,降低内存峰值
config.optimization = config.optimization || {};
config.optimization.splitChunks = false;
}
return config;
},
};
export default nextConfig;
④ 跳过 Turbo Prune — 直接构建(大幅提速)
对于小项目,turbo prune 本身的开销可能比它节省的还大。创建一个简化版 Dockerfile:
# Wrote apps/web/Dockerfile.slim
# ============================================
# 低配服务器优化版 Dockerfile — 跳过 Turbo Prune
# ============================================
# 适用场景:1核1G / 2核2G 等低资源服务器
# 优势:省去 turbo prune 阶段,直接构建,内存占用更低
# ============================================
FROM node:22-slim AS base
RUN corepack enable
ENV NODE_OPTIONS="--max-old-space-size=512"
ENV NEXT_TELEMETRY_DISABLED=1
ENV Pnpm_enableCorepack=true
# 复制依赖声明文件
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
# 安装所有依赖(利用 Docker 层缓存)
RUN --mount=type=cache,id=pnpm,target=/root/.pnpm-store \
pnpm install --frozen-lockfile --prefer-offline
# 复制源代码
COPY . .
# 构建 — 限制并发,避免内存峰值
RUN CONCURRENT_TASKS=1 pnpm turbo build --filter=nodebbs-web --concurrency=1
# ============================================
# 生产环境运行时
# ============================================
FROM node:22-slim AS runner
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3100
ENV HOSTNAME=0.0.0.0
ENV NODE_OPTIONS="--max-old-space-size=512"
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
COPY --from=base --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
COPY --from=base --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
COPY --from=base --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
USER nextjs
EXPOSE 3100
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD node -e "require('http').get('http://localhost:3100', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
CMD ["node", "apps/web/server.js"]
部署到远程服务器的完整步骤
# 1. 在服务器上创建 Swap
sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# 2. 使用简化版 Dockerfile 构建(跳过 turbo prune)
docker build -f apps/web/Dockerfile.slim -t nodebbs-web .
# 3. 或者用 docker-compose,指定 service
# docker-compose.yml 中修改:
# dockerfile: apps/web/Dockerfile.slim
---
优化效果对比
措施 预计提升
创建 2G Swap 从 OOM 崩溃 → 能跑完,+∞%
NODE_OPTIONS=512MB 减少 GC 频率,+30-40%
跳过 Turbo Prune(用 Dockerfile.slim) 省去一层 COPY + prune 命令,+20-30%
--concurrency=1 避免内存峰值导致 swap 抖动,+15%
optimizePackageImports 补充 减少 tree-shaking 时间,+5-10%
如果还是太慢的终极方案
考虑升级到 2核 4G 服务器。1核 1G 跑 Next.js 编译属于极端场景,即使优化后首次构建仍可能需要 10-20 分钟。长期来看,升级服务器的性价比远高于持续优化编译速度。