Serverless Framework: Setting up a custom domain to API Gateway
Adding a meaningful domain name for API Gateway using serverless configuration.
When we deploy our APIs using the Serverless Framework
, it provides endpoints like, https://api-id.execute-api.region.amazonaws.com/stage
. By using a custom domain we can make the endpoint name much more meaningful.
According to AWS docs,
Custom domain names are simpler and more intuitive URLs that you can provide to your API users.
With Serverless Framework
, it is very easy and straightforward to set up a custom domain by adding some configuration in our serverless.yml
file.
Prerequisite
Before we go further, we have to ensure,
- AWS CLI is installed in local machine
- Serverless framework is installed in local machine
- Node.js v12.13.0 in installed in local machine
- A hosted zone is setup
Route 53
with a domain - An SSL certificate is installed for the domain and its sub-domains
Create a Sample Project
We will use a popular serverless-typescript boilerplate. First, create a project,
serverless install --url https://github.com/AnomalyInnovations/serverless-typescript-starter --name my-serverless-project
Go to the project root directory and install the dependencies,
cd my-serverless-project
npm install
Update the region from the serverless.yml
file. Since, I am in ap-south-1
region, in my case, under provider
the region
should be ap-south-1
.
Deploy the project to AWS
by,
sls deploy
As output, we should get an endpoint like, https://9pmx5phid6.execute-api.region-name.amazonaws.com/dev/hello
If we go to the link, we will see a success message that indicates, out API and lambda function is working.
Creating Custom Domain
To create a custom domain using the serverless framework, we will need a plugin named serverless-domain-manager.
Install the serverless-domain-manager
in the project as a dev dependency,
npm install -D serverless-domain-manager
Now add the plugin to the serverless.yml
file.
Now, we have to create a new section in the serverless.yml
file, named custom
,
custom:
customDomain:
domainName: my-sub-domain.my-domain.com
basePath: "v1"
stage: ${self:provider.stage}
certificateName: original-domain
createRoute53Record: true
Here,
domainName, the new domain name, that will replace the arbitrary auto created endpoint.
basePath, This will replace the stage name.
stage, This is the stage name, will be replaced by API version
or basePath
.
certificateName, SSL certified domain or sub-domain
createRoute53Record, Will automatically create a record in the hosted zone in Route53
Our final serverless.yml
file should be very much be like the following,
service: host-service
package:
individually: true
plugins:
- serverless-bundle # Package our functions with Webpack
- serverless-offline
- serverless-dotenv-plugin # Load .env as environment variables
- serverless-domain-manager
provider:
name: aws
runtime: nodejs12.x
stage: dev
region: ap-south-1
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
custom:
customDomain:
domainName: host-api.my-tour-assistant.com
basePath: "v1"
stage: ${self:provider.stage}
certificateName: my-tour-assistant.com
createRoute53Record: true
Create the domain,
sls create_domain
Now deploy the app again and it will do the mapping,
sls deploy
After deployment is completed, if we go to the https://domainName/basePath/hello
, we should see the success message as JSON format as expected.
In my case, the new URL becomes https://host-api.my-tour-assistant.com/v1/hello
.
Our custom domain is now integrated with the API-Gateway.
Handle Multiple Stage with Serverless Domain Manager
There could be a scenario, where we want to do the mapping for the production and development environment.
We want to run the dev API in dev.domainName/basePath
and prod API in domainName/basePath
.
In this case, our custom
section of the serverless.yml
file should be,
custom:
domain:
dev: tour-api-dev.my-tour-assistant.com
prod: tour-api.my-tour-assistant.com
customDomain:
domainName: ${self:custom.domain.${opt:stage, 'dev'}}
basePath: "v1"
stage: ${self:provider.stage}
certificateName: my-tour-assistant.com
createRoute53Record: true
In this case, when we create the domain, we have to specify the stage. For example, create domain,
sls create_domain --stage dev # for dev API
sls create_domain --stage prod # for prod API
Similarly, when we deploy the app to AWS, we have to specify the stage also,
SLS_DEBUG=* sls deploy --stage dev -v # Deploy the app to the development environment
sls deploy --stage prod -v # Deploy the app to the production environment
For any queries or clarifications, please let me know.
For more AWS articles, take a look at my AWS Series.