y.y
Published on

在Docker中为Next.js应用配置HTTPS:完整指南

在Docker中为Next.js应用配置HTTPS:完整指南

在现代web开发中,安全性至关重要。本文将详细指导你如何在Docker环境中为Next.js应用配置HTTPS。我们将使用mkcert生成本地信任的SSL证书,在Dockerfile中进行必要的配置,并使用docker-compose来简化部署过程。

先决条件

  • 安装Docker和Docker Compose
  • 基本的Next.js应用
  • Node.js和npm/yarn/pnpm

步骤1: 准备Dockerfile

首先,我们需要创建一个Dockerfile来构建我们的Next.js应用。这个Dockerfile包含多个阶段:依赖安装、应用构建和最终的运行时镜像。

创建一个名为Dockerfile的文件,内容如下:

FROM node:18-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 curl
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
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

# Install mkcert manually
RUN curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" \
    && chmod +x mkcert-v*-linux-amd64 \
    && mv mkcert-v*-linux-amd64 /usr/local/bin/mkcert

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

# Generate SSL certificate
RUN mkcert -install
RUN mkcert localhost 0.0.0.0 192.168.2.50

# 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 public folder
COPY --from=builder /app/public ./public

# Copy SSL certificates
COPY --from=builder /app/localhost+2.pem ./localhost+2.pem
COPY --from=builder /app/localhost+2-key.pem ./localhost+2-key.pem

# Set the correct permissions for certificate files
RUN chown nextjs:nodejs localhost+2.pem localhost+2-key.pem \
    && chmod 644 localhost+2.pem \
    && chmod 600 localhost+2-key.pem

# 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 ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/next.config.mjs ./next.config.mjs

USER nextjs

EXPOSE 10085

ENV PORT 10085
ENV HOSTNAME "0.0.0.0"

# Use HTTPS with Next.js
CMD ["node", "-e", "\
const https = require('https');\
const fs = require('fs');\
const { parse } = require('url');\
const next = require('next');\
\
const dev = process.env.NODE_ENV !== 'production';\
const app = next({ dev, dir: __dirname });\
const handle = app.getRequestHandler();\
\
const options = {\
  key: fs.readFileSync('localhost+2-key.pem'),\
  cert: fs.readFileSync('localhost+2.pem')\
};\
\
app.prepare().then(() => {\
  https.createServer(options, (req, res) => {\
    const parsedUrl = parse(req.url, true);\
    handle(req, res, parsedUrl);\
  }).listen(process.env.PORT, process.env.HOSTNAME, (err) => {\
    if (err) throw err;\
    console.log(`> Ready on https://${process.env.HOSTNAME}:${process.env.PORT}`);\
  });\
});\
"]

这个Dockerfile做了以下几件事:

  1. 使用node:18-alpine作为基础镜像。
  2. 安装项目依赖和mkcert工具。
  3. 生成自签名SSL证书。
  4. 构建Next.js应用。
  5. 设置生产环境并复制必要的文件。
  6. 配置HTTPS服务器启动命令。

步骤2: 创建docker-compose.yml文件

为了简化部署过程,我们将创建一个docker-compose.yml文件。在你的项目根目录创建这个文件,内容如下:

version: '3'

services:
  nextjs-app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "10085:10085"
    environment:
      - NODE_ENV=production
      - PORT=10085
      - HOSTNAME=0.0.0.0
    restart: unless-stopped

这个docker-compose文件定义了一个服务nextjs-app,它使用我们刚才创建的Dockerfile来构建镜像,并设置了必要的环境变量和端口映射。

步骤3: 构建和运行

现在,你可以使用以下命令来构建和运行你的Docker容器:

docker-compose up --build

这个命令会构建Docker镜像(如果需要的话)并启动容器。等待构建过程完成后,你应该会看到类似这样的输出:

> Ready on https://0.0.0.0:10085

现在你可以在浏览器中访问https://localhost:10085https://192.168.2.50:10085来查看你的应用。

注意事项

  1. 首次访问时,你可能会看到浏览器的安全警告,因为我们使用的是自签名证书。你可以选择继续访问该网站。

  2. 如果你想在后台运行容器,可以使用docker-compose up -d --build命令。

  3. 要停止应用,可以运行docker-compose down

  4. 这个设置主要用于开发环境。在生产环境中,你可能需要使用更复杂的SSL配置和证书管理策略。

  5. 确保在使用自签名证书时,将根证书添加到你的系统和浏览器的信任存储中。

  6. 在实际部署时,你可能需要根据你的具体网络设置调整IP地址和端口。

  7. 始终确保你的next.config.jsnext.config.mjs文件被正确复制到Docker镜像中。

结论

通过遵循这些步骤,你现在应该有一个在Docker容器中运行的、支持HTTPS的Next.js应用了。这不仅提高了你的应用的安全性,还为你提供了一个一致的开发和部署环境。

使用Docker和docker-compose简化了部署过程,使得在不同环境中运行你的应用变得更加容易。记住要根据你的具体需求调整配置,特别是在准备生产环境部署时。