Custom Domain Names¶
In this tutorial, we’re going to create a REST API and associate our own custom domain with this REST API. This allows us to not use the auto-generated domain name that API Gateway automatically creates when we deploy our REST API.
Installation and Configuration¶
If you haven’t already setup and configured Chalice, see the Quickstart for a step by step guide. You can run these commands to create a basic Chalice app:
$ python3 --version
Python 3.7.3
$ python3 -m venv venv37
$ . venv37/bin/activate
$ python3 -m pip install chalice
$ chalice new-project customdomain
$ cd customdomain
Configure and Deploy a REGIONAL Endpoint¶
Before we configure a custom domain for our REST API, we’ll deploy our REST API so we can see the auto-generated domain name that API Gateway creates for us.
First, we’ll change our endpoint type from EDGE (the default) to REGIONAL.
Update your .chalice/config.json
file so it looks like this:
$ cat .chalice/config.json
{
"version": "2.0",
"app_name": "customdomain",
"api_gateway_endpoint_type": "REGIONAL",
"stages": {
"dev": {
"api_gateway_stage": "api"
}
}
}
Now we’ll deploy our application. Note the URL that’s printed when your application is deployed.
$ chalice deploy
Creating deployment package.
Creating IAM role: customdomain-dev
Creating lambda function: customdomain-dev
Creating Rest API
Resources deployed:
- Lambda ARN: arn:aws:lambda:us-west-2:12345:function:customdomain-dev
- Rest API URL: https://qxea58abcd.execute-api.us-west-2.amazonaws.com/api/
You now have an API up and running using API Gateway and Lambda:
$ curl https://qxea58abcd.execute-api.us-west-2.amazonaws.com/api/
{"hello": "world"}
The qxea58abcd.execute-api.us-west-2.amazonaws.com
domain name was
auto-generated by API Gateway. Replacing this domain name with our own
custom domain name allows us to use simpler and more intuitive URLs that
we can provide to our API users.
Configuring a Custom Domain¶
In this tutorial, we’re using Amazon Route53 to manage our DNS configuration. If you’re using a third-party domain registrar, the steps will be similar, but you will have to create your DNS records using your provider’s web interface or API.
For this tutorial, we’ll configure the domain chalice-demo-app.com
. Be
sure to replace this value with your own domain name.
Creating a Hosted Zone¶
First, we’ll need to create a hosted zone in Route 53. If you already have a hosted zone created for your domain, you can skip this step.
We’ll be using the AWS CLI V2 to configure our domain. You can follow the installation instructions if you don’t have the AWS CLI installed.
$ aws route53 create-hosted-zone --name chalice-demo-app.com --caller-reference 12345
{
"Location": "https://route53.amazonaws.com/2013-04-01/hostedzone/ZABCDEFGABCDEFGLDO822",
"HostedZone": {
"Id": "/hostedzone/ZABCDEFGABCDEFGLDO822",
"Name": "chalice-demo-app.com.",
"CallerReference": "12345",
"Config": {
"PrivateZone": false
},
"ResourceRecordSetCount": 2
},
"ChangeInfo": {
"Id": "/change/C07395431VDLB0CY65VP",
"Status": "PENDING",
"SubmittedAt": "2020-07-21T17:13:54.709000+00:00"
},
"DelegationSet": {
"NameServers": [
"ns-123.awsdns-31.net",
"ns-123.awsdns-05.com",
"ns-123.awsdns-09.org",
"ns-123.awsdns-40.co.uk"
]
}
}
You’ll need to save the value of the hosted zone id for later.
From the output above the line "Id": "/hostedzone/ZABCDEFGABCDEFGLDO822",
contains our hosted zone id of ZABCDEFGABCDEFGLDO822
. We’ll refer
to this value as $OUR_HOSTED_ZONE_ID
later.
You’ll now need to register the "NameServers"
shown in the output above
with your domain registrar.
Creating an ACM Certificate¶
Now that we have our hosted zone, we’ll need to create an ACM certificate
associated with this domain. This is the SSL/TLS certificate that will be
used when requests are made to our custom domain. In this example, we’ll
create a wildcard certificate for *.chalice-demo-app.com
. Note that
we’re creating a REGIONAL
endpoint type for our REST API, which means
that our ACM certificate must be in the same region as our REST API.
In this example, we’re using us-west-2
. If you’re using the default
EDGE
endpoint type, the ACM cert must be in us-east-1
. You can
explicitly specify the region using the --region
CLI parameter if needed.
$ aws acm request-certificate --domain-name "*.chalice-demo-app.com" \
--validation-method DNS --idempotency-token 12345 \
--options CertificateTransparencyLoggingPreference=DISABLED
{
"CertificateArn": "arn:aws:acm:us-west-2:0123456789:certificate/578efbda-6bc7-4ae2-9964-6e6c3f58008b"
}
Save the value of CertificateArn
shown in the output above. We’ll
need this value when we configure our app to use this custom domain.
Before we can use this certificate, we need to validate this certificate.
This process demonstrates that we own or control the domain name associated
with the certificate.
In the command above, we used the --validation-method DNS
, which
requires us to add CNAME records to validate we control our domain name.
ACM supports both DNS validation
as well as email validation.
To validate our domain, we’ll now create the necessary CNAME records in our
hosted zone using the Route53 API. First, we need to retrieve the values
for our CNAME record. Be sure to replace the value of --certificate-arn
with your own certificate ARN in the command below:
$ aws acm describe-certificate --certificate-arn arn:aws:acm:us-west-2:0123456789:certificate/578efbda-6bc7-4ae2-9964-6e6c3f58008b \
--query Certificate.DomainValidationOptions[0]
{
"DomainName": "*.chalice-demo-app.com",
"ValidationDomain": "*.chalice-demo-app.com",
"ValidationStatus": "PENDING_VALIDATION",
"ResourceRecord": {
"Name": "_1234567891234567897eb5512d9fb554.chalice-demo-app.com.",
"Type": "CNAME",
"Value": "_123456789123456789e7495341c27cd1.jfrzftwwjs.acm-validations.aws."
},
"ValidationMethod": "DNS"
}
Next we’ll create a CNAME record for
_1234567891234567897eb5512d9fb554.chalice-demo-app.com.
with a value of
_123456789123456789e7495341c27cd1.jfrzftwwjs.acm-validations.aws.
:
$ aws route53 change-resource-record-sets \
--hosted-zone-id $OUR_HOSTED_ZONE_ID --change-batch \
'{
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "_0073e080112eb8de8c7eb5512d9fb554.chalice-demo-app.com.",
"Type": "CNAME",
"TTL": 300,
"ResourceRecords": [{"Value": "_6e560a5a9831aad210e7495341c27cd1.jfrzftwwjs.acm-validations.aws."}]
}
}
]
}'
# Command output:
{
"ChangeInfo": {
"Id": "/change/C0339874QPDDRA8TKT7U",
"Status": "PENDING",
"SubmittedAt": "2020-07-21T17:36:39.902000+00:00"
}
}
It will take a few minutes before ACM validates your domain. You can
move on to the next steps, or if you’d like to wait until the domain is
validated you can use the CLI’s certificate-validated
waiter, which
will block until the ACM certificate is validated:
$ aws acm wait certificate-validated \
--certificate-arn arn:aws:acm:us-west-2:0123456789:certificate/578efbda-6bc7-4ae2-9964-6e6c3f58008b
Chalice App Configuration¶
Now that we have our hosted zone and ACM certificate created, we can configure
our Chalice application with our custom domain. To do so we need to add
api_gateway_custom_domain
configuration option and specify our ACM certificate ARN as well as the our
custom domain name. You’re .chalice/config.json
file should look like
this:
{
"version": "2.0",
"app_name": "customdomain",
"api_gateway_endpoint_type": "REGIONAL",
"stages": {
"dev": {
"api_gateway_custom_domain": {
"domain_name": "api.chalice-demo-app.com",
"certificate_arn": "arn:aws:acm:us-west-2:0123456789:certificate/578efbda-6bc7-4ae2-9964-6e6c3f58008b"
},
"api_gateway_stage": "api"
}
}
}
We we rerun the chalice deploy
command you’ll notice there’s a new
Custom domain name:
line in the output:
$ chalice deploy
Creating deployment package.
Updating policy for IAM role: customdomain-dev
Updating lambda function: customdomain-dev
Updating rest API
Creating custom domain name: api.chalice-demo-app.com
Creating api mapping: /
Resources deployed:
- Lambda ARN: arn:aws:lambda:us-west-2:0123456789:function:customdomain-dev
- Rest API URL: https://qxea58abcd.execute-api.us-west-2.amazonaws.com/api/
- Custom domain name:
HostedZoneId: Z1UJRXOUMOOFQ8
AliasDomainName: d-6vj4cynstd.execute-api.us-west-2.amazonaws.com
Now that we’ve configured our Chalice app with our custom domain, there’s one step left. We need to update our DNS configuration to point to our REST API.
To do this, we’ll use the values of HostedZoneId
and AliasDomainName
in the output above to create an alias record in our hosted zone.
Alias Record Configuration¶
You can run the following command to create an alias record to your REST API.
Note that there are two different hosted zone id values here. The value
specified as the --hosted-zone-id
value is the ID of our hosted zone
ID ($OUR_HOSTED_ZONE_ID
) that we created earlier in this example.
The value of the HostedZoneId
in the AliasTarget
section is the
value of the HostedZoneId
generated by API Gateway shown in the output
of chalice deploy
above.
$ aws route53 change-resource-record-sets --hosted-zone-id ZABCDEFGABCDEFGLDO822 --change-batch \
'{
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "api.chalice-demo-app.com",
"Type": "A",
"AliasTarget": {
"DNSName": "d-6vj4cynstd.execute-api.us-west-2.amazonaws.com",
"HostedZoneId": "Z1UJRXOUMOOFQ8",
"EvaluateTargetHealth": false
}
}
}
]
}'
# Command output:
{
"ChangeInfo": {
"Id": "/change/C0539657Y0HMX8XBC5EH",
"Status": "PENDING",
"SubmittedAt": "2020-07-21T17:52:34.935000+00:00"
}
}
Verification¶
Our Chalice application is now configured to use our custom domain.
We can verify this by making a request to our custom domain. In this
example, this is api.chalice-demo-app.com
:
$ curl -i https://api.chalice-demo-app.com/
HTTP/1.1 200 OK
Date: Tue, 21 Jul 2020 17:56:00 GMT
Content-Type: application/json
Content-Length: 17
Connection: keep-alive
x-amzn-RequestId: 9f33fbb9-6b10-469e-827f-f287199c9bc5
x-amz-apigw-id: QCPXoEwPIAMFi8Q=
X-Amzn-Trace-Id: Root=1-5f172c30-dccc232932a16a539dfc01b9;Sampled=0
{"hello":"world"}
Next Steps¶
For more information on configuring custom domains, check out our topic guide on custom domains as well as the config file reference for the api_gateway_custom_domain and the websocket_api_custom_domain options.