Custom Domain Names, CloudFront, & SSL
The new API Gateway HTTP API makes it easy to configure your application with a custom domain name using CloudFormation. These steps will get you there.
If your custom domain name needs a CloudFront distribution for edge caching use this guide with one small change to step #4 above.
Route53 Information
The following steps assume you have a domain managed by Route53. Before proceeding you will need the Hosted Zone ID for the domain zone you are going to use.
- AWS Console -> Route53
- Click on "Hosted zones"
- Click on your hosted zone. Ex:
example.com
- Click on "Hosted zone details" at the top.
- Note the "Hosted zone ID". Ex:
ZSZCGGTST3201
SSL/TLS Certificate with ACM
We are going to use AWS Certificate Manager to secure your HTTPS traffic under your custom domain. Again, this assumes your domain is setup in Route53 since you will need to validate the certificate and AWS makes that super easy with DNS.
- AWS Console -> Certificate Manager
- Click "Request a certificate" button.
- Select "Request a public certificate", and "Request a certificate" button.
- Domain name. Ex:
*.example.com
- Click "Next"
- Select "DNS validation", and "Review".
- Click "Confirm and request" button.
- Click the tiny disclosure triangle beside your domain name.
- Click the "Create record in Route 53" button then "Create" again in modal.
- Click "Continue"
Verification will take about 3 minutes. From the Certificate Manager dashboard, you can wait and/or hit the đ button and the Status will change from "Pending validation" to "Issued".
SSM Template Parameters
âšī¸ Skip this section if you do not need to deploy your application to distinct staging & production AWS accounts. If so, make sure to replace the references to both CertificateArn
and HostedZoneId
in step #4's CloudFormation code.
In this example we are going to use a more interesting form of Environment & Configuration. Instead of environment variables for our application, we want to leverage another CloudFormation Parameter for our SAM template.yaml
file. Using SSM parameter types will allow the template to use differnt domain names when deployed to different AWS accounts. Add these to the Parameters:
section of your template.yaml
file.
HostedZoneId:
Type: 'AWS::SSM::Parameter::Value<String>'
Default: '/config/route53/example.com'
CertificateArn:
Type: 'AWS::SSM::Parameter::Value<String>'
Default: '/config/ssl/cert/example.com'
Open up SSM in each AWS account and create a new parameter for each path above. The value for HostedZoneId
would be from step #1 above and CertificateArn
would be from step #2.
CloudFormation Code
Once we have both our Hosted Zone ID and the ARN of our SSL certificate, we can use CloudFormation in our SAM template.yaml
file to create our custom domain name. We are going to use the following resources.
Add this YAML code to the Resources:
section of your template.yaml
file. Remember to:
- Replace
www.example.com
with your domain name. - If your HTTP API resource differs from
RailsHttpApi
, use that name instead. - If you opted out of step #3, replace these with your literal values:
!Ref HostedZoneId
!Ref CertificateArn
RailsDomainName:
Type: AWS::ApiGatewayV2::DomainName
Properties:
DomainName: www.example.com
DomainNameConfigurations:
- CertificateArn: !Ref CertificateArn
EndpointType: REGIONAL
SecurityPolicy: TLS_1_2
RailsApiMapping:
Type: AWS::ApiGatewayV2::ApiMapping
DependsOn: RailsDomainName
Properties:
ApiId: !Ref RailsHttpApi
DomainName: www.example.com
Stage: !Ref RailsEnv
RailsRecordSet:
Type: AWS::Route53::RecordSetGroup
DependsOn: RailsApiMapping
Properties:
HostedZoneId: !Ref HostedZoneId
RecordSets:
- Name: www.example.com
Type: A
AliasTarget:
HostedZoneId: !GetAtt RailsDomainName.RegionalHostedZoneId
DNSName: !GetAtt RailsDomainName.RegionalDomainName
EvaluateTargetHealth: false
From here you can do a ./bin/deploy
. You can now access your Rails application's API Gateway HTTP API using a custom domain name.
CloudFront Distribution
This part is optional and requires a small chage to step #4 above by removing the RailsRecordSet
resource from your template.yaml
file. The goal here is to set your domain name www.example.com
as an alias to this CloudFront distribution.
Before you begin, you need the "API Gateway domain name" that was created via the AWS::ApiGatewayV2::DomainName
resource above. You can find it by doing the following. It will look something like d-xxxxxxxxxx.execute-api.us-east-1.amazonaws.com
.
- AWS Console -> API Gateway
- Click "Custom domain names" on the left panel.
- Select your domain name in the list.
- Under "Endpoint configuration" find "API Gateway domain name"
Here are the steps to create your CloudFront Distribution:
- AWS Console -> CloudFront -> Create Distribution -> Web -> Get Started
- Origin Domain Name: d-xxxxxxxxxx.execute-api.us-east-1.amazonaws.com
- Origin Path: /production (or your deployed stage/env)
- Minimum Origin SSL Protocol: TLSv1.2
- Origin Protocol Policy: HTTPS Only
- Origin Custom Headers: X-Forwarded-Host www.example.com (â ī¸ IMPORTANT)
- Viewer Protocol Policy: Redirect HTTP to HTTPS
- Allowed HTTP Methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
- Cached HTTP Methods: OPTIONS
- Cache Based on Selected Request Headers: Whitelist - Accept (â ī¸ Allows
respond_to
to work) - Object Caching: Use Origin Cache Headers
- Forward Cookies: All
- Query String Forwarding and Caching: Forward all, cached based on all
- Compress Objects Automatically: Yes
- Alternate Domain Names (CNAMEs): www.example.com
- SSL Certificate: Custom SSL Certificate (select *.example.com from step above)
This process takes a while to fully deploy. Once done you will have a CloudFront domain name looking something like dxxxxxxxxxxxxx.cloudfront.net
. Head to Route53 and create an alias for www.example.com
to this CloudFront distibution domain name.