Next.js 应用的 Docker 部署完整指南 | 从本地开发到生产环境部署

本文详细介绍了如何使用 Docker 将 Next.js 应用部署到生产环境的完整流程。涵盖了从本地开发环境搭建、Docker 配置、Docker Compose 多服务部署,到服务器配置、Nginx 设置和 HTTPS 证书申请的全过程。文章还包含了性能优化建议和安全性最佳实践,适合需要将 Next.js 应用容器化部署的开发者阅读。

阅读时长: 5 分钟
共 2282字
作者: eimoon.com

一.基础环境准备

需要准备基本的node环境和docker ,可以通过下面的命令检查。

检查node环境:

node -v

检查docker是否安装:

docker version

二、nextjs的部署方式

可以查看nextjs官方文档,nextjs 有多种部署方式,最简单的是使用vercel部署。但是,如果您希望通过 AWS、Google Cloud 或其他云提供商运行您的应用,则可以使用docker部署。

  • Vercel 平台部署(最简单)
  • Docker 容器化部署(更灵活,适合自托管)
  • 静态导出部署
  • 传统服务器部署

本文重点介绍 Docker 部署方案。

三、添加配置

使用docker部署,我们需要先添加一下nextjs的配置,在nextj.config.js文件中,添加下面的配置

// next.config.js
module.exports = {
  // ... rest of the configuration.
  output: "standalone",
};

这个配置主要用于优化生产环境部署,特别是在 Docker 容器化场景中。他会生成一个独立部署包,创建一个完全独立的生产构建,包含所有必需的依赖和文件。

四、编写Dockerfile

对于Dockerfile文件的编写,我们不需要自己来完成,可以直接使用nextjs的案例来修改:

# syntax=docker.io/docker/dockerfile:1
# 可以适当提高一下版本,这里我把node18修改为了20
FROM node:20-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED=1

RUN \
  if [ -f yarn.lock ]; then yarn run build; \
  elif [ -f package-lock.json ]; then npm run build; \
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
  else echo "Lockfile not found." && exit 1; \
  fi

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT=3000

# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

这里部署使用的是多阶段部署,另外添加了用户组和用户,除了可以适当修改一下node版本,其他不用修改。

五、本地运行测试

进入你的项目目录,运行构建镜像

docker build -t nextjs-docker .

然后测试运行

docker run -p 3000:3000 nextjs-docker

alt text

页面正常运行。但是这样只是运行了一个前端页面,如果链接数据库和api,可以会出现问题,所以我们需要使用docker compose来进行多服务器部署。

六、使用docker-compose部署

在本地我后端使用的是go和postgresq运行的,扫描我本地的资料文件夹,然后写入数据库,提供给前端数据。这里设置后端的内容我不展开,我的docker compose文件是这样的,我们只关注nextjs服务。


services:
  postgres:
    image: postgres:14-alpine
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=dbname
    ports:
      - "5432:5432"
    volumes:
      - data-volume:/var/lib/postgresql/data
      - ./backend/files.sql:/docker-entrypoint-initdb.d/files.sql

  api:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    environment:
      - DB_SOURCE=postgresql://user:password@postgres:5432/dbname?sslmode=disable
    depends_on:
      - postgres
    restart: unless-stopped
    entrypoint:
      [
        "/app/wait-for.sh",
        "postgres:5432",
        "--",
        "/app/start.sh"
      ]
    command: [ "/app/main" ]

  nextjs:
    build:
      context: ./frontend # 指向 Next.js 项目的目录
      dockerfile: Dockerfile # 确保该路径下存在 Dockerfile
    ports:
      - "3000:3000" # Next.js 默认端口
    environment:
      - NEXT_PUBLIC_API_URL=http://api:8080 # API 服务地址
    depends_on:
      - api # 确保 API 服务先启动
volumes:
  data-volume:

networks:
  default:
    name: app-network

nexjts部分各个配置参考注释。关闭运行中的nextjs和后端接口。然后我们在docker compose 文件的目录,运行

docker compose up -d

当完成后,同样打开localhost:3000 ,可以看到同样的页面。现在本地运行正常后,我们把他部署到服务器上面。

七、上传到服务器上

使用git来管理前/后端的项目,当然你也可以使用git submodule一个仓库来管理.然后把修改上传到github上面。

git add .
git commit -m "init"
git push origin main

八、服务器部署

现在使用 ssh 登陆到你的服务器。你需要配置你的github账户在服务器上的权限,参考github文档

一般直接在home目录clone,可能没有写入权限,可以先到tmp文件夹中clone后,然后移动到你的工作目录。

git clone ‘你前/后端github地址’

同样检查你的服务上的node和docker环境。和本地运行类似,运行

sudo docker compose up -d

等待服务构建。如果出现问题,可以检查服务状态和日志: 检查服务状态

sudo docker compose ps -a

检查日志,检查其中的api服务,最后10行日志:

sudo docker compose logs api --tail 10

九、配置域名

在服务器上构建的时候,我们先配置一个域名,进入你的域名管理机构,添加一个a解析到你服务器上。例如在cloudflare上:

alt text

修改前缀,并把1.1.1.1 替换为你的服务器地址。代理状态,可以暂时设置为仅dns,等我们申请完ssl证书后再打开。

十、nginx配置

针对刚刚解析的域名,我们配置一下nginx,这里只做几个主要的配置。进入到/etc/nginx/conf.d,复制一下defult.conf 文件。

sudo cp default.conf you_domain.conf

然后修改一下里面的内容,主要是server_name ,和proxy_pass 这两部分。

server {
    server_name  你的域名; # 修改为你的域名
    listen 80;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
	proxy_pass http://127.0.0.1:3000; # 转发到本地的 3000 端口
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

}

测试一下,访问你的域名,能正常访问到nginx默认页面(在docker compose 未运行的情况下)。

十、测试部署

现在docker compose 应该构建完成了,然后我们测试一下,访问你的域名,可以和本地一样,正常访问到你的页面,

alt text

我们的docker compose部署就完成了。

可以看到页面还会提示http 不安全,所以后续你需要配置一下免费ssl安全证书.

十一、申请免费的安全证书

这里申请免费安全证书不详细介绍,可以使用 certbot 或者acme.sh来完成,可以参考我以前的文章,使用certbot申请免费安全证书或者使用acme.sh申请免费安全证书

总结

本文介绍了使用 Docker 部署 Next.js 应用的完整流程。通过合理的配置和优化,可以构建一个高性能、安全且易于维护的生产环境部署方案。在实践中,根据具体项目需求调整配置参数,添加更多安全的配置,更多的性能优化,日志自动监控等设置,并持续关注性能监控和安全更新。

微信公众号

使用 Hugo 构建
主题 StackJimmy 设计