如何将React/Next.js构建产物部署到AWS S3并通过CloudFront运行?
问题:如何将Next.js应用部署到AWS S3 + CloudFront
我正在构建React/Next.js应用,计划将其部署至AWS S3,并通过AWS CloudFront提供服务(以该S3桶作为分发源)。我会自行处理Route53及DNS配置,将域名(例如https://myapp.example.com)映射到CloudFront分发。
官方文档提到可以用以下命令以生产模式构建并运行Next.js应用:
npm run build npm run start
但我希望把npm run build生成的产物(可能是.next/目录的内容?)上传到S3桶,让用户访问域名时,通过CloudFront获取S3中的构建产物并直接在浏览器运行。
请问该如何实现这一需求?S3需要存储哪些内容?是否需要特殊配置才能让应用正常运行?
实现步骤与配置说明
1. 先明确Next.js的部署模式
S3只能托管静态资源,所以首先要区分你的应用类型:
- 如果你的应用没有使用SSR(
getServerSideProps/getInitialProps)、ISR等需要服务器运行的逻辑,可以用Next.js的静态导出模式,这是唯一能直接部署到S3的方案。 - 如果依赖SSR/ISR,仅S3+CloudFront无法支撑,需要搭配Lambda@Edge或者改用Vercel等托管服务,这里只讲纯静态部署的场景。
开启静态导出的配置:
在next.config.js中添加:
module.exports = { output: 'export', }
然后执行构建:
npm run build
此时项目根目录会生成out/文件夹,这就是完整的静态产物目录,直接上传它到S3即可。
2. S3需要存储的内容
静态导出后,out/目录下的所有文件都要上传到S3桶的根目录,包括:
- 页面HTML文件(比如
index.html、about.html) _next/目录:包含转译后的JS、CSS、图片等静态资源(带哈希后缀,用于缓存更新)public/目录下的自定义静态资源(会被复制到out/根目录)
如果没开静态导出,.next/目录包含服务器端运行代码,S3无法执行,所以不能直接使用。
3. S3桶的关键配置
- 静态网站托管:开启该功能,设置默认首页为
index.html,错误页也设为index.html(解决Next.js单页应用的路由跳转问题)。 - 访问权限:推荐用CloudFront的Origin Access Control(OAC)或Origin Access Identity(OAI)限制仅CloudFront能访问S3资源,避免直接暴露S3桶。示例桶策略(适配OAI):
{ "Version": "2008-10-17", "Id": "PolicyForCloudFrontPrivateContent", "Statement": [ { "Sid": "1", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity YOUR_OAI_ID" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*" } ] } - CORS配置(如果需要跨域请求):
[ { "AllowedHeaders": ["*"], "AllowedMethods": ["GET", "HEAD"], "AllowedOrigins": ["https://myapp.example.com"], "ExposeHeaders": [] } ]
4. CloudFront的关键配置
- 源设置:选择你的S3桶作为源,关联OAC/OAI,确保只有CloudFront能拉取S3资源。
- 缓存行为:
- 对
_next/*路径的静态资源,设置长缓存时间(比如1年),因为这些资源带哈希后缀,内容更新时文件名会自动变化。 - 对HTML文件,设置短缓存时间(比如5分钟),或者配置缓存键包含查询字符串,确保内容更新时用户能获取最新版本。
- 对
- 错误页面:将404错误重定向到
/index.html,状态码设为200,保证Next.js客户端路由正常工作。 - 自定义域名与HTTPS:配置CloudFront使用你的自定义域名,关联AWS Certificate Manager(ACM)的SSL证书(注意证书必须在us-east-1区域申请)。
5. 上传产物到S3的方式
- 使用AWS CLI(推荐):
# 同步out目录到S3,删除桶中本地不存在的文件 aws s3 sync out/ s3://YOUR_BUCKET_NAME --delete - 控制台手动上传:直接上传
out/目录下的所有文件,保持原有目录结构。
常见问题排查
- 子路由访问404:检查CloudFront错误页面配置和S3静态网站托管的错误页设置是否为
index.html。 - 资源加载失败:确认CloudFront缓存行为允许访问
_next/路径,且S3桶权限配置正确。 - 缓存更新不及时:发布新版本后,可手动触发CloudFront缓存失效,或者依赖静态资源的哈希后缀自动更新缓存。
内容的提问来源于stack exchange,提问作者hotmeatballsoup
相关产品推荐
相关产品推荐

