DEV Community

Cover image for Serverless Framework + AWS: automatically creating certificate and domain for your app
Tiago Boeing for AWS Community Builders

Posted on • Originally published at tiagoboeing.Medium

Serverless Framework + AWS: automatically creating certificate and domain for your app

This is a guide showing how you can automatically create an SSL certificate on Amazon Certificate Manager (ACM) and configure a subdomain on Route 53 Hosted Zone using Serverless Framework with some wonderful plugins.

Before start:

Firstly, you need to know that we'll use some Serverless Framework plugins to turn our life easier:

Note: I’ll show some scripts using NodeJS, but Serverless Framework can be used on almost any language (to not say literally anywhere).


With this in mind, let's go ahead! Start installing dependencies:

npm install serverless-domain-manager serverless-certificate-creator —-save-dev

Create a custom domain section

I usually separate domains to allow customization for each one, it would be like this in my stack:

# serverless.yml
...

custom:
  domains:
    # References to 'prod' stage
    prod:
      domainName: api.tiagoboeing.com
      certificateName: api.tiagoboeing.com

    # References to 'dev' stage  
    dev:
      domainName: api-dev.tiagoboeing.com
      certificateName: api-dev.tiagoboeing.com

    ...
Enter fullscreen mode Exit fullscreen mode

Of course, the certificate name is chosen by you. I only like to use the same name of the domain to keep easier to locate on ACM.

This is the way how I organize my apps, take this as an example to customize/start.

See our custom section:

custom:
  # Amazon Certificate Manager
  customCertificate:
    # Route 53 Hosted Zone name
    # don't forget the dot on the end!
    hostedZoneNames: "tiagoboeing.com."

    # Here we get our certificate name inside custom.domain.STAGE.certificateName
    # STAGE will be automatically filled with the value from "provider > stage"
    certificateName: ${self:custom.domains.${self:provider.stage}.certificateName}

    region: ${self:provider.region}

  # Route53
  customDomain:
    # Get value from "domains" section using stage that is being deployed
    domainName: ${self:custom.domains.${self:provider.stage}.domainName}

    # Same case of certificaName inside customCertificate
    certificateName: ${self:custom.domains.${self:provider.stage}.certificateName}

    # Enable plugin to create an A Alias and AAAA Alias records in Route53
    # mapping the domainName to the generated distribution domain name.
    createRoute53Record: true

    # Enable plugin to autorun create_domain/delete_domain as part of sls deploy/remove
    autoDomain: true
Enter fullscreen mode Exit fullscreen mode

Deploy

Take the following tips and tricks:

To create the certificate on ACM run:

serverless create-cert

# or

npx serverless create-cert
Enter fullscreen mode Exit fullscreen mode

Create the certificate on the deploying stage, you can change the stage using --stage prod flag or STAGE=prod env.

Create domain - simply run

To create domain on Route 53, use:

serverless create_domain

# or

npx serverless create_domain
Enter fullscreen mode Exit fullscreen mode

Keep in mind that createRoute53Record and autoDomain were enabled on serverless.yml, a simple serverless deploy will start automatically this step.

Deploying to another stage (not on the default: dev) you need to use the option --stage (read more here). As an example for the first time you can use:

# First deploy PROD stage

serverless create-cert --stage=prod

serverless deploy --stage=prod
Enter fullscreen mode Exit fullscreen mode

It’s possible to manually generate a domain using serverless-domain-manager, you can do it using the command serverless create_domain, this isn’t needed if you have the autoDomain flag enabled (as mentioned earlier).

Complete stack

See the complete Serverless stack below.

service: sls-my-app

plugins:
  - serverless-domain-manager
  - serverless-certificate-creator

provider:
  name: aws
  runtime: nodejs14.x
  stage: ${opt:stage, 'dev'}
  region: ${opt:region, 'us-east-1'}
  apiGateway:
    shouldStartNameWithService: true
  timeout: 5

  # passing base domain name and stage to our functions
  environment:
    DOMAIN: ${self:custom.customDomain.domainName}
    STAGE: ${self:provider.stage}

functions:
  authenticate:
    handler: src/functions/hello.handler
    description: "Return a hello world"
    timeout: 3
    events:
      - http:
          method: GET
          path: /
          cors: true

custom:
  domains:
    prod:
      domainName: api.tiagoboeing.com
      certificateName: api.tiagoboeing.com
    dev:
      domainName: api-dev.tiagoboeing.com
      certificateName: api-dev.tiagoboeing.com

  # Amazon Certificate Manager
  customCertificate:
    hostedZoneNames: "tiagoboeing.com." # don't forget the dot on the end - is required by Route53
    certificateName: ${self:custom.domains.dev.certificateName}
    region: ${self:provider.region}

  # Route53
  customDomain:
    domainName: ${self:custom.domains.${self:provider.stage}.domainName}
    certificateName: ${self:custom.domains.dev.certificateName}
    createRoute53Record: true
    autoDomain: true
Enter fullscreen mode Exit fullscreen mode

📝 Thanks, Paulo Weber by the review this text.

Read more

PT-BR:

Top comments (0)