Next.js环境下的Docker+Nginx配置

99 阅读2分钟

直接上代码....

  1. 主要是两个服务: Next.js 服务和Nginx服务

Dockerfile

# Use Node.js 18 Alpine image as the base image for all stages
FROM node:18-alpine AS base

# Install necessary dependencies
FROM base AS deps

# Install libc6-compat for compatibility
RUN apk add --no-cache libc6-compat  

WORKDIR /app

# Set npm registry to mirror
ENV NPM_CONFIG_REGISTRY=https://registry.npmmirror.com/  

# Copy the package.json and lock files, then install dependencies
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./

# Use Yarn if yarn.lock is present
# Use npm if package-lock.json is present
# Use pnpm if pnpm-lock.yaml is present
# Exit if no lockfile is found
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

# Build the application
FROM base AS builder

WORKDIR /app

# Copy installed dependencies from the 'deps' stage
COPY --from=deps /app/node_modules ./node_modules  

# Copy the rest of the application code
COPY . .  


RUN \
  # Build using Yarn if yarn.lock is present
  if [ -f yarn.lock ]; then yarn run build; \  
  # Build using npm if package-lock.json is present
  elif [ -f package-lock.json ]; then npm run build; \  
  # Build using pnpm if pnpm-lock.yaml is present
  elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \  
  # Exit if no lockfile is found
  else echo "Lockfile not found." && exit 1; \  
fi

# Run the application
FROM base AS runner

WORKDIR /app

# Set environment to production
ENV NODE_ENV production  

# Add system group for nodejs user
RUN addgroup --system --gid 1001 nodejs  

# Add system user for Next.js with UID 1001
RUN adduser --system --uid 1001 nextjs  

# Copy necessary files from the builder stage
COPY --from=builder /app/public ./public

# Create the .next directory
RUN mkdir .next  

# Change ownership of the .next directory
RUN chown nextjs:nodejs .next  

# Copy the compiled application from the builder stage and set the correct ownership
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

# Switch to the non-root user 'nextjs'
USER nextjs  

# Expose port 5173 for the application
EXPOSE 5173  

# Set the port to 5173
ENV PORT 5173  

# Allow the app to be accessed from any IP
ENV HOSTNAME "0.0.0.0"  

# Run the app using Node.js
CMD ["node", "server.js"]  

docker-compose.yml

version: '3.8'

services:
  app:
    container_name: app  # 设置 app 服务的容器名称
    build:
      context: . 
    ports:
      - '5173:5173'
    environment:
      - NODE_ENV=production
      - PORT=5173
    networks:
      - cosette-net
    restart: always
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5173"]
      interval: 30s
      retries: 3
      start_period: 5s
      timeout: 10s

  nginx:
    container_name: nginx  # 设置 nginx 服务的容器名称
    image: nginx:alpine
    ports:
      - '80:80'
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app
    networks:
      - cosette-net
    restart: always
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/"]
      interval: 30s
      retries: 3
      start_period: 5s
      timeout: 10s

networks:
  cosette-net:
    driver: bridge

next.config.ts

import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  /* config options here */
  output: 'standalone'
}

export default nextConfig

nginx\default.conf

server {
    listen 80;

    # Server name
    server_name localhost;

    location / {
        # Proxy pass to the application
        proxy_pass http://app:5173;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /_next/static/ {
        # Serve static files from Next.js
        # alias /.next/static/;
        # Disable access logs
        # access_log off;
        # Set cache expiration
        # expires max;
        # Add cache control header
        # add_header Cache-Control "public, max-age=31536000, immutable";

        proxy_pass http://app:5173/_next/static/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    # Error log file
    error_log /var/log/nginx/error.log;

    # Access log file
    access_log /var/log/nginx/access.log;
}

nginx\Dockerfile

FROM nginx:alpine

# Remove any existing config files
RUN rm /etc/nginx/conf.d/*

# Copy config files
# *.conf files in "conf.d/" dir get included in main config
COPY ./default.conf /etc/nginx/conf.d/

# Expose the listening port
EXPOSE 80

# Launch NGINX
CMD [ "nginx", "-g", "daemon off;" ]