This package is heavily inspired by Remix's Architect starter (arc
deployment option in npx create-remix
).
When deploying to AWS Lambda with the Serverless framework, you'll need:
sls
or serverless
)Serverless recommends installing the serverless cli globally:
npm i -g serverless
During development, we will use the standard remix dev
command.
npm run dev
If you want to use serverless-offline
with some aspects of your project, you'll need to run that as a separate script, or use something like concurrently to run both processes in one command.
Open up http://localhost:3000 and you should be ready to go!
Before you can deploy, you'll need to install the AWS CLI.
If you want to use the Serverless Dashboard, you'll need to configure the Serverless CLI and add the app
key to your serverless.yml
file.
If you make it through all of that, you're ready to deploy!
build the app for production:
npm run build
Deploy with sls
sls deploy
You're in business!
There's a deploy
script in package.json
already that will handle both parts if that's your thing.
# stage defaults to "dev"
npm run deploy
# or
npm run deploy -- --stage production
# or
yarn deploy --stage production
The first deployment will take a little while longer because it has to set up the CloudFront distribution, so expect it to take about 5 minutes.
After deploying, if you want to visit your CloudFront endpoint, you can run sls info --verbose
to get the WebsiteDomain
output from the Cloudformation stack.
After deploying, you'll have an S3 bucket for storing static assets, your Remix app running in AWS Lambda behind API Gateway, and CloudFront as a CDN in front of both services.
There is a limitation when using CloudFront with API Gateway that CloudFront cannot forward the Host
header. This means that there isn't a default way to know which
domain a user is requesting from by default. This makes request.url
in Remix show the API Gateway domain instead of the CloudFront domain, which will be noticeable
when using redirects from actions and loaders or building URLs from the request URL. In order to address this,you need to add the X-Forwarded-Host
to the origin cache
policy for API Gateway. The @remix-run/architect
adapter will read this header when transforming the API Gateway request for the Remix request handler.
sls info --verbose
to get the WebsiteDomain
from "Stack Outputs"serverless.yml
under custom > dev > HOST
and uncomment the OriginCustomHeaders
block for the RemixOrigin
.Follow the deployment steps.
WebsiteDomain
If you use a custom domain for your CloudFront distribution, you can skip to the next section.
After the deployment completes, run the following in your terminal at the project root:
sls info --verbose
You'll get an output similar to the following:
Serverless: Running "serverless" installed locally (in service node_modules)
Service Information
service: remix-serverless-app
stage: dev
region: us-east-1
stack: remix-serverless-app-dev
resources: 16
api keys:
None
endpoints:
ANY - https://xxxxxxxxxxxxx.execute-api.us-east-1.amazonaws.com/{proxy+}
functions:
remix: remix-serverless-app-dev-remix
layers:
None
Stack Outputs
WebsiteDomain: xxxxxxxxxxxx.cloudfront.net
WebsiteBucketName: remix-serverless-app-dev-websitebucket-somerandomid
DistributionID: XXXXXXXXXXXX
HttpApiId: xxxxxxxxxxxxx
RemixLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:xxx:function:remix-serverless-app-dev-remix:1
ServerlessDeploymentBucketName: remix-serverless-app-dev-serverlessdeploymentbuck-xxxxxxxx
HttpApiUrl: https://xxxxxxxxxxxxx.execute-api.us-east-1.amazonaws.com
From this output, copy the WebsiteDomain
value from the "Stack Outputs" section.
In serverless.yml, add paste the copied WebsiteDomain value.
custom:
dev:
HOST: xxxxxxxxxxxx.cloudfront.net # Replace this value
Then, uncomment the OriginCustomHeaders
block:
OriginCustomHeaders:
- HeaderName: X-Forwarded-Host
HeaderValue: ${self:${self:provider.stage}.HOST}
sls deploy
# or npm run deploy
After deploying, your Remix app will use the domain from the X-Forwarded-Host header as the domain.
You'll want to add a domain for the prod
or any other deployment stages you intend to use as well. If you configure CloudFront to use a custom domain, you will need to use your custom domain as the value instead of the CloudFront default.