You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用AWS CDK搭建Remix项目?求从零开始的搭建教程

从零搭建基于AWS CDK的Remix项目

整体架构原理

Remix项目拆分静态资源与服务端逻辑分别部署:

  • 静态资源(样式、客户端脚本、静态文件)存放在S3私有桶,通过CloudFront做全球CDN分发,加速访问
  • 动态路由、API请求由AWS Lambda处理,通过API Gateway作为入口,再由CloudFront统一转发请求
  • AWS CDK以代码形式定义所有基础设施(S3、Lambda、CloudFront、API Gateway、IAM权限),实现一键部署与维护

分步搭建步骤

1. 初始化Remix项目

创建基础Remix项目,选择自定义部署模式:

npx create-remix@latest remix-cdk-app
  • 选择「Just the basics」模板
  • 部署目标选「None」(后续自行适配AWS)
  • 按需选择TypeScript/JavaScript

进入项目目录后,调整remix.config.js适配AWS环境:

/** @type {import('@remix-run/dev').AppConfig} */
export default {
  serverBuildTarget: "node-cjs", // 适配Node.js Lambda运行环境
  publicPath: "/build/", // 静态资源路径,对应CloudFront+S3的访问路径
  server: "./server/index.js", // 自定义Lambda入口文件
  ignoredRouteFiles: ["**/.*"],
};

2. 配置Lambda入口文件

在项目根目录创建server/index.js(TypeScript则用.ts),作为Lambda的请求处理入口:

import { createRequestHandler } from "@remix-run/node";
import * as build from "../build/server/index.js";

// 处理Lambda收到的HTTP请求
export const handler = createRequestHandler({
  build,
  mode: process.env.NODE_ENV || "production",
});

3. 初始化AWS CDK项目

在Remix项目根目录初始化CDK项目(确保本地已配置AWS CLI凭证):

cdk init app --language typescript

安装所需CDK依赖包:

npm install @aws-cdk/aws-s3 @aws-cdk/aws-cloudfront @aws-cdk/aws-cloudfront-origins @aws-cdk/aws-lambda @aws-cdk/aws-apigateway @aws-cdk/aws-iam @aws-cdk/aws-s3-deployment

4. 编写CDK栈定义

打开lib/remix-cdk-app-stack.ts,替换为以下代码,定义所有AWS资源:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';
import * as path from 'path';

export class RemixCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // 1. 创建存储静态资源的私有S3桶
    const staticBucket = new s3.Bucket(this, 'RemixStaticBucket', {
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      removalPolicy: cdk.RemovalPolicy.DESTROY, // 测试环境用,生产环境改为RETAIN
    });

    // 2. 创建处理动态请求的Lambda函数
    const remixServerLambda = new lambda.Function(this, 'RemixServerLambda', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset(path.join(__dirname, '../build/server')),
      environment: {
        NODE_ENV: 'production',
      },
      memorySize: 256,
      timeout: cdk.Duration.seconds(10),
    });

    // 3. 创建API Gateway代理Lambda
    const api = new apigateway.LambdaRestApi(this, 'RemixApiGateway', {
      handler: remixServerLambda,
      proxy: true,
    });

    // 4. 创建CloudFront分发,统一静态/动态请求路由
    const cloudfrontOAC = new cloudfront.OriginAccessControl(this, 'CloudFrontOAC', {
      originAccessControlOriginType: cloudfront.OriginAccessControlOriginType.S3,
      signingBehavior: cloudfront.OriginAccessControlSigningBehavior.ALWAYS,
      signingProtocol: cloudfront.OriginAccessControlSigningProtocol.SIGV4,
    });

    // 允许CloudFront访问S3桶
    staticBucket.addToResourcePolicy(new cdk.aws_iam.PolicyStatement({
      actions: ['s3:GetObject'],
      resources: [staticBucket.arnForObjects('*')],
      principals: [new cdk.aws_iam.ServicePrincipal('cloudfront.amazonaws.com')],
      conditions: {
        StringEquals: {
          'AWS:SourceArn': `arn:aws:cloudfront::${cdk.Aws.ACCOUNT_ID}:distribution/*`,
        },
      },
    }));

    const distribution = new cloudfront.Distribution(this, 'RemixCloudFrontDist', {
      defaultBehavior: {
        origin: new origins.RestApiOrigin(api),
        viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
      },
      additionalBehaviors: {
        // 静态资源路由到S3
        '/build/*': {
          origin: new origins.S3Origin(staticBucket, { originAccessControl: cloudfrontOAC }),
          viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
        '/assets/*': {
          origin: new origins.S3Origin(staticBucket, { originAccessControl: cloudfrontOAC }),
          viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
      },
    });

    // 5. 自动上传Remix静态资源到S3
    new s3deploy.BucketDeployment(this, 'RemixStaticDeployment', {
      sources: [
        s3deploy.Source.asset(path.join(__dirname, '../public')),
        s3deploy.Source.asset(path.join(__dirname, '../build/client')),
      ],
      destinationBucket: staticBucket,
      distribution,
      distributionPaths: ['/*'], // 触发CloudFront缓存刷新
    });

    // 输出CloudFront域名
    new cdk.CfnOutput(this, 'CloudFrontDomain', {
      value: distribution.distributionDomainName,
    });
  }
}

5. 构建并部署

  1. 先构建Remix项目:
npm run build
  1. 部署CDK栈:
cdk deploy

部署完成后,控制台会输出CloudFront的域名,访问该域名即可验证Remix项目是否正常运行。


关键注意事项

  • 环境变量:如果Remix需要访问AWS服务或其他配置,可通过CDK的lambda.Function的environment参数注入,敏感信息建议用AWS Secrets Manager或Parameter Store
  • 缓存策略:可根据业务调整CloudFront的缓存策略,比如动态请求禁用缓存,静态资源设置较长缓存时间
  • Lambda性能:根据请求量调整Lambda的内存和超时时间,内存越高,CPU性能越强
  • 生产环境配置:将S3桶的removalPolicy改为cdk.RemovalPolicy.RETAIN,防止误删数据;添加自定义域名到CloudFront

内容的提问来源于stack exchange,提问作者Oliver Darby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 07:45:37