如何使用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. 构建并部署
- 先构建Remix项目:
npm run build
- 部署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
相关产品推荐
相关产品推荐

