生产环境部署
你已经开发了一个 Payload 应用,完成了全面测试,并且在本地运行良好。现在是时候发布了。太棒了!做得好! 那么接下来该做什么呢?
有多种方式可以将 Payload 部署到生产环境。在评估如何部署 Payload 时,你需要考虑以下主要方面:
Payload 可以部署在任何能运行 Next.js 的地方——包括 Vercel、Netlify、SST、DigitalOcean、AWS 等等。由于它是开源的,你也可以自行托管。
但重要的是要记住,大多数 Payload 项目还需要数据库、文件存储、邮件服务提供商和 CDN。无论选择哪种部署平台,请确保满足项目的所有需求。
通常,最简单快捷的部署方式是使用 Payload Cloud——它能开箱即用地提供你所需的一切,包括:
- MongoDB Atlas 数据库
- S3 文件存储
- Resend 邮件服务
- Cloudflare CDN
- 蓝绿部署
- 日志
- 以及其他更多功能
基础配置
Payload 完全运行在 Next.js 中,因此构建 Payload 时会使用 Next.js 构建流程。如果你使用 create-payload-app
创建项目,执行 build
npm 脚本将为生产环境构建 Payload。
安全性
Payload 提供了一系列安全功能,你可以依赖它们来增强应用的安全性。在部署到生产环境时,最好再次检查你是否正确使用了每一项功能。
密钥(Secret Key)
初始化 Payload 时,你需要提供一个 secret
属性。这个属性应该是无法猜测的,并且极难被暴力破解。确保你的生产环境 secret
是一个长且复杂的字符串。
仔细检查并全面测试所有访问控制
由于 你 完全掌控着谁可以对你的数据执行哪些操作,因此在部署到生产环境之前,应该反复检查以确保你负责任地行使这一权力。
默认情况下,所有访问控制功能都要求用户成功登录 Payload 才能创建、读取、更新或删除数据。
但是,例如如果你允许公开用户注册,则需要确保你的访问控制函数更加严格 - 只允许适当的用户执行适当的操作。
生产环境运行
根据你部署 Payload 的位置,可能需要向部署平台提供一个启动脚本,以便在生产模式下启动 Payload。
请注意,这与运行 next dev
不同。通常,Next.js 应用会配置一个 start
脚本,该脚本会运行 next start
。
安全 Cookie 设置
你应该为生产环境的 Payload 实例使用 SSL 证书,这意味着你可以在启用了身份验证的 Collection 配置中启用安全 cookie。
防止 API 滥用
Payload 内置了一套强大的防滥用措施,例如在多次登录失败后锁定用户、GraphQL 查询复杂度限制、最大 depth
设置等。点击此处了解更多。
数据库
Payload 可以与任何 Postgres 数据库或 MongoDB 兼容的数据库(包括 AWS DocumentDB 或 Azure Cosmos DB)一起使用。确保你的生产环境可以访问 Payload 使用的数据库。
开箱即用的 Payload 模板会将 process.env.DATABASE_URI
环境变量传递给其数据库适配器,因此请确保你的部署平台已分配该环境变量(以及你使用的所有其他变量)。
DocumentDB
当使用 AWS DocumentDB 时,你需要在传递给 mongooseAdapter
的 connectOptions
中配置认证连接选项。同时需要将 connectOptions.useFacet
设置为 false
来禁用不支持的 $facet
聚合操作。
CosmosDB
当使用 Azure Cosmos DB 时,任何需要排序的字段都需要建立索引。要为管理界面中可能排序的所有字段添加排序索引,可以使用 indexSortableFields 选项。
文件存储
如果你使用 Payload 来管理文件上传,就需要考虑上传文件将永久存储在何处。如果你不使用 Payload 进行文件上传,那么本节内容对你的应用没有任何影响。
持久化 vs 临时文件系统
一些云应用托管服务如 Heroku 使用 临时
文件系统,这意味着上传到服务器的文件只会在服务器重启或关闭前存在。Heroku 和类似提供商会不受控制地安排重启和关闭,导致你的上传文件会意外消失且无法恢复。
相反,持久化文件系统永远不会删除你的文件,可以可靠地永久托管上传内容。
使用临时文件系统的流行云提供商:
- Heroku
- DigitalOcean Apps
使用持久化文件系统的流行云提供商:
- DigitalOcean Droplets
- Amazon EC2
- GoDaddy
- 许多其他传统网络主机
警告:
如果你依赖 Payload 的上传功能,请确保使用具有持久化文件系统的主机,或者与 Amazon S3 等第三方文件托管服务集成。
使用云存储提供商
如果你不使用 Payload 的 upload
功能,可以完全忽略本节内容。
但如果你使用上传功能,同时又想使用临时文件系统存储,你可以选择 Payload 官方提供的云存储插件,或者自己编写适配器,将用户上传的文件保存到更持久的存储解决方案中,如 Amazon S3 或 DigitalOcean Spaces。
Payload 提供了一系列官方云存储适配器供你选择:
按照文档说明配置这些存储提供商。对于本地开发环境,将上传文件存储在本地电脑可能更方便,而在生产环境中,只需启用你选择的云存储插件即可。
Docker
这是一个用于生产环境的 Payload 多阶段 Docker 构建示例。请确保在部署时设置了必要的环境变量,如 PAYLOAD_SECRET
、PAYLOAD_CONFIG_PATH
和 DATABASE_URI
(如果需要)。如果你的构建需要数据库连接但不想实际连接数据库,可以参考这里了解如何避免这种情况。
在你的 Next.js 配置中,设置 output
属性为 standalone
。
// next.config.js
const nextConfig = {
output: 'standalone',
}
Dockerfile
# Dockerfile
# 来自 https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
FROM node:18-alpine AS base
# 仅在需要时安装依赖
FROM base AS deps
# 请参考 https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine 了解为何可能需要安装 libc6-compat
RUN apk add --no-cache libc6-compat
WORKDIR /app
# 根据首选的包管理器安装依赖
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 "未找到锁文件。" && exit 1; \
fi
# 仅在需要时重新构建源代码
FROM base AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
# Next.js 会收集完全匿名的遥测数据用于分析使用情况。
# 了解更多:https://nextjs.org/telemetry
# 如果你想在构建时禁用遥测,请取消以下行的注释。
# 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 "未找到锁文件。" && exit 1; \
fi
# 生产环境镜像,复制所有文件并运行 next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
# 如果你想在运行时禁用遥测,请取消以下行的注释。
# ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY /app/public ./public
# 为预渲染缓存设置正确的权限
RUN mkdir .next
RUN chown nextjs:nodejs .next
# 自动利用输出追踪来减小镜像体积
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY /app/.next/standalone ./
COPY /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
# server.js 由 next build 从独立输出创建
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD HOSTNAME="0.0.0.0" node server.js
Docker Compose
以下是可用于开发的 docker-compose.yml 文件示例
version: '3'
services:
payload:
image: node:18-alpine
ports:
- '3000:3000'
volumes:
- .:/home/node/app
- node_modules:/home/node/app/node_modules
working_dir: /home/node/app/
command: sh -c "corepack enable && corepack prepare pnpm@latest --activate && pnpm install && pnpm dev"
depends_on:
- mongo
# - postgres
env_file:
- .env
# 确保你的 DATABASE_URI 使用 'mongo' 作为主机名,例如 mongodb://mongo/my-db-name
mongo:
image: mongo:latest
ports:
- '27017:27017'
command:
- --storageEngine=wiredTiger
volumes:
- data:/data/db
logging:
driver: none
# 取消以下注释以使用 postgres
# postgres:
# restart: always
# image: postgres:latest
# volumes:
# - pgdata:/var/lib/postgresql/data
# ports:
# - "5432:5432"
volumes:
data:
# pgdata:
node_modules: