CloudFormation部署React应用至CloudFront遇源站连接失败求助
问题描述
尝试用CloudFormation栈将React应用从S3桶部署上线,访问CloudFront URL时出现如下错误:
ERROR
Failed to contact the origin.
以下是CloudFormation模板文件:
AWSTemplateFormatVersion: 2010-09-09 Parameters: ProjectSource: Type: String Default: "https://github.com/..." Description: "Source control URL (e.g. Github)" GithubOwner: Type: String Default: (myaccount) GithubRepo: Type: String Default: (myrepo) GithubOAuthToken: Type: String Default: "(my token)" Description: "Github personal access token" GithubBranch: Type: String Default: master Description: "e.g. master or main" Resources: CodePipeline: Type: 'AWS::CodePipeline::Pipeline' Properties: RoleArn: !GetAtt CodePipeLineRole.Arn ArtifactStore: Location: !Ref PipelineBucket Type: S3 Stages: - Name: Source Actions: - Name: SourceAction ActionTypeId: Category: Source Owner: ThirdParty Provider: GitHub Version: 1 OutputArtifacts: - Name: NameForOutput Configuration: Owner: !Ref GithubOwner Repo: !Ref GithubRepo Branch: !Ref GithubBranch OAuthToken: !Ref GithubOAuthToken - Name: Build Actions: - Name: BuildAction ActionTypeId: Category: Build Owner: AWS Version: 1 Provider: CodeBuild InputArtifacts: - Name: (NameHere) OutputArtifacts: - Name: (NameBuild) Configuration: ProjectName: !Ref CodeBuild CodeBuildRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - "codebuild.amazonaws.com" Action: - "sts:AssumeRole" Path: /service-role/ Policies: - PolicyName: root PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "s3:GetObject" - "s3:GetObjectVersion" - "s3:GetBucketVersioning" - "s3:PutObject" Resource: - !GetAtt PipelineBucket.Arn - !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]] - Effect: Allow Action: - "s3:GetObject" - "s3:GetObjectVersion" - "s3:GetBucketVersioning" - "s3:PutObject" - "s3:PutObjectAcl" Resource: - !GetAtt DeployBucket.Arn - !Join ['', [!GetAtt DeployBucket.Arn, "/*"]] - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" - "cloudfront:CreateInvalidation" Resource: - "*" CodePipeLineRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - "codepipeline.amazonaws.com" Action: - "sts:AssumeRole" Policies: - PolicyName: root PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - "s3:GetObject" - "s3:GetObjectVersion" - "s3:GetBucketVersioning" - "s3:PutObject" Resource: - !GetAtt PipelineBucket.Arn - !Join ['', [!GetAtt PipelineBucket.Arn, "/*"]] - Effect: Allow Action: - "codebuild:BatchGetBuilds" - "codebuild:StartBuild" Resource: "*" CodeBuild: Type: 'AWS::CodeBuild::Project' Properties: Name: !Sub ${AWS::StackName}-CodeBuild ServiceRole: !GetAtt CodeBuildRole.Arn Artifacts: Type: CODEPIPELINE Name: MyProject Source: Type: CODEPIPELINE Environment: ComputeType: BUILD_GENERAL1_SMALL Type: LINUX_CONTAINER Image: "aws/codebuild/nodejs:10.14.1" Source: Type: CODEPIPELINE BuildSpec: !Sub | version: 0.1 phases: pre_build: commands: - echo Installing source NPM dependencies... - npm install build: commands: - echo Build started on `date` - npm run build post_build: on-failure: CONTINUE commands: - aws s3 cp --recursive --acl public-read ./build s3://${DeployBucket}/ #uncomment if you have service-worker.js #- aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/service-worker.js s3://${DeployBucket}/ - aws s3 cp --acl public-read --cache-control="max-age=0, no-cache, no-store, must-revalidate" ./build/index.html s3://${DeployBucket}/ - aws cloudfront create-invalidation --distribution-id ${Distribution} --paths /index.html /service-worker.js artifacts: files: - '**/*' base-directory: build PipelineBucket: Type: 'AWS::S3::Bucket' Properties: {} DeployBucket: Type: 'AWS::S3::Bucket' Properties: WebsiteConfiguration: IndexDocument: index.html Distribution: Type: "AWS::CloudFront::Distribution" Properties: DistributionConfig: Origins: - DomainName: !GetAtt DeployBucket.DomainName Id: !Ref DeployBucket S3OriginConfig: OriginAccessIdentity: '' DefaultRootObject: index.html Enabled: true DefaultCacheBehavior: MinTTL: 86400 MaxTTL: 31536000 ForwardedValues: QueryString: true TargetOriginId: !Ref DeployBucket ViewerProtocolPolicy: "redirect-to-https"
问题分析与修复方案
核心问题1:CloudFront Origin配置不兼容
当前模板中CloudFront的Origin使用了S3网站域名(!GetAtt DeployBucket.DomainName),但配置了S3OriginConfig,这会导致CloudFront尝试通过S3 REST API访问桶,而非网站端点,两者不兼容是导致“无法连接源站”的主要原因。
修复方式:
将CloudFront Origin改为使用自定义源配置,指向S3网站URL:
Distribution: Type: "AWS::CloudFront::Distribution" Properties: DistributionConfig: Origins: - DomainName: !Select [1, !Split ['//', !GetAtt DeployBucket.WebsiteURL]] Id: !Ref DeployBucket CustomOriginConfig: HTTPPort: 80 HTTPSPort: 443 OriginProtocolPolicy: "http-only" # S3网站端点仅支持HTTP DefaultRootObject: index.html Enabled: true DefaultCacheBehavior: MinTTL: 86400 MaxTTL: 31536000 ForwardedValues: QueryString: true TargetOriginId: !Ref DeployBucket ViewerProtocolPolicy: "redirect-to-https"
核心问题2:S3桶访问权限不足
即使CodeBuild将文件设为public-read,如果桶本身没有允许公开读取的策略,CloudFront仍无法获取内容。需给DeployBucket添加桶策略:
DeployBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref DeployBucket PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: "*" Action: "s3:GetObject" Resource: !Join ['', [!GetAtt DeployBucket.Arn, "/*"]]
其他模板问题修复
- CodePipeline输入输出名称不匹配:Source阶段输出名称为
NameForOutput,但Build阶段输入名称写的是(NameHere),需统一:# Source阶段OutputArtifacts OutputArtifacts: - Name: SourceOutput # Build阶段InputArtifacts InputArtifacts: - Name: SourceOutput - CodeBuild重复定义Source属性:删除重复的
Source配置,保留包含BuildSpec的那一项:CodeBuild: Type: 'AWS::CodeBuild::Project' Properties: Name: !Sub ${AWS::StackName}-CodeBuild ServiceRole: !GetAtt CodeBuildRole.Arn Artifacts: Type: CODEPIPELINE Name: MyProject Source: Type: CODEPIPELINE BuildSpec: !Sub | # 原BuildSpec内容 Environment: ComputeType: BUILD_GENERAL1_SMALL Type: LINUX_CONTAINER Image: "aws/codebuild/nodejs:10.14.1" - Node.js版本过旧:建议将CodeBuild镜像升级到较新版本,比如
aws/codebuild/amazonlinux2-x86_64-standard:4.0(内置Node.js 16+),避免依赖安装失败。
验证步骤
- 更新模板后重新部署CloudFormation栈
- 确认CodePipeline执行完成,Build阶段成功将React构建产物上传到
DeployBucket - 直接访问S3网站URL验证内容是否正常
- 访问CloudFront URL,确认错误消失
内容的提问来源于stack exchange,提问作者Joshua Foxworth
相关产品推荐
相关产品推荐

