Adding a Custom Domain and SSL to AWS EC2
Tags: aws, docker, javascript, tutorial
Published: 2022-01-14 18:36:46

In our [previous article](https://dev.to/alvinslee/spinning-up-a-nodejs-server-in-a-container-on-aws-with-ec2-i2i), we Dockerized our Node.js server, pushed that container image to AWS ECR, and then launched an EC2 instance with that container running inside. With our network and security group configured, we could send HTTP requests to our EC2 instance (at port `80`) and receive responses from our server.

For our next trick, let's set up a custom domain name and make our server accessible via HTTPS. Here are the steps we're going to take:

1. Create a hosted zone for our domain in Route 53.
2. Create an SSL certificate for our custom domain AWS Certificate Manager.
3. Create a target group which our application load balancer will forward requests to.
4. Create an application load balancer for our EC2.
5. Update our security group to allow traffic on port `443`.
6. Create a Route 53 record to route subdomain requests to our load balancer.

# Create A Hosted Zone

For this walkthrough, we'll assume that you have already purchased a domain name, and that you would like to point a subdomain to the server you are running on EC2. To route the subdomain to the correct resource and to request an SSL certificate for this subdomain, you'll need to create a hosted zone in AWS Route 53.

On the "hosted zones" page, click on "Create hosted zone."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v3zroje86uen7yw5ns4h.png)

Enter the domain name (that you control), select the "public hosted zone" type, and click "Create." You'll see the newly created hosted zone in your list. Click on it. You'll see several name servers listed in the NS record.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1vnxejur8rpomdlim6lg.png)

You will need to login to the service where you purchased and manage this domain. At that service, you will need to set the name servers to use these values provided by AWS. This will give Route 53 control to handle subsequent domain (and subdomain) routing.

# Create an SSL Certificate

With your domain set up in Route 53, requesting an SSL certificate for your subdomain is quick and simple. Go to AWS Certificate Manager. **Make sure that you are in the same region where you deployed your EC2 instance.**

Click on "Request a certificate" to request a public certificate.

Enter the domain name that you want to use for accessing your server. For our demo, we will use `node-server-demo.codingplus.coffee`. Select "DNS validation" as the validation method.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j5niw3d3tkeygqg36668.png)

Your certificate will now be listed, but its status will be "Pending validation." Click on it to see more details.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1w8qjggdxjxr8lc2fda7.png)

To issue the certificate, you need to verify that you control this domain. With "DNS validation," this is done by creating a publicly accessible CNAME record with a specific key and value—something that only the owner of a domain is able to do. Fortunately, because you are now managing your domain in Route 53, you can tell Certificate Manager to create the necessary validation record for you. Click on "Create records in Route 53."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gpktztosxytbg7nk0op3.png)

If you look back at the DNS records for your hosted zone, you'll see that there's a new CNAME record in the list.

After a few minutes, the Certificate Manager will show your certificate as successfully verified and issued. We have our certificate. It's time to use it.

# Create a Target Group

We will need to set up a few more AWS resources in order to get HTTPS access to the server on our EC2 instance. Ultimately, we will need an application load balancer (ALB). That ALB will need to listen for requests on port 443, and then forward those requests to a target group. The target group will take those requests and distribute them appropriately to registered targets. In our setup, we only have one target—our EC2 instance.

We'll start by creating the target group. Go to the AWS EC2 service. Make sure you are working in the region where you launched your EC2 instance. Navigate to the "Target Groups" page. Click on "Create target group."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vbpqfg8r3zfflvuqjtoq.png)

Our target type will be "Instances."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hol4xyhv669jg1nd5mjc.png)

Choose a name for your target group. We'll go with `node-server-ec2-instances`. For protocol, choose "HTTP" at port `80`. For protocol version, choose "HTTP1."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ukcc42ufdwnd85wo7dpa.png)

For the health check protocol, choose "HTTP", leave the health check path as `/`, and choose to override the health check port, using port `80`. This is the port that is open on our EC2 instance, and a request to `/` will be a request to our Node.js server at the `/` path, which is an accessible endpoint.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vclghaqc5osxd9ptf6hp.png)

Lastly, you'll need to register targets for the group. Select your EC2 instance, making sure to use port `80`, and then click on "Include as pending below."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8v9xkbnwvixrz18xyvrb.png)

Finally, click on "Create target group" to finalize your target group creation.

At this point, if you poke around, you'll see that your target group is listed as "unused" because it is not configured to receive traffic from the load balancer. It's time to create one.

# Create an Application Load Balancer

In the EC2 service sidebar, click on "Load Balancers." On that page, click on "Create Load Balancer." From the different load balancer types, choose "Application Load Balancer" and click on "Create."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24pjv8ge6fuft9tz5ebs.png)

## Basic Configuration

Choose a name for your load balancer. We'll go with `node-server-alb`. For "scheme," choose "Internet-facing." For "IP address type," choose "IPv4."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/359541ra6wwdwq9hlaok.png)

## Network Mapping

Under "Mappings," you will need to choose at least two availability zones to which your load balancer will route traffic. One of the availability zones you choose must be the availability zone where your EC2 instance resides. To find out which zone that is, you can look at the network settings for your EC2 instance. In a production environment, you would probably have multiple EC2 instances (all serving up the same application), spread out across multiple availability zones. The job of the load balancer is to distribute traffic among healthy targets across those zones.

## Security Group

In our previous post, we created a security group for our EC2 instance. This security group opened up inbound traffic on ports `22` and `80`. Choose this same security group for the load balancer. (In a later step, we will need to open up inbound traffic on port `443` as well.)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zv16hn4rqdcdoqr09ai6.png)

## Listeners and Routing

Our ALB will listen for HTTPS requests on port `443`, and then forward those requests to a target group. Find the target group you just created in the drop-down list.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lscuncd1b498qyd9qoym.png)

## Secure Listener Settings

For this setting, use the default security policy. Then, choose an SSL certificate "From ACM," finding the newly-created certificate in the drop-down.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rh7lb04138o78dcph8or.png)

Lastly, click on "Create load balancer" to finalize. AWS will begin provisioning your load balancer.

## Add Listener for Redirecting Port `80` Traffic To Port `443`

We would also like our load balancer to listen for any traffic on port `80`, and then redirect that traffic, using HTTPS, to port `443`. While your load balancer is being provisioned, go to its "Listeners" settings and click on "Add listener."

Use these settings to add the listener:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ak1jgctbrjgkrsb9ry0m.png)

You'll see the newly created listener in your list. However, you'll also notice a little alert triangle next to your HTTPS `443` listener.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/br5b4nfe6xmqkngm7l2o.png)

Oh, that's right. We set up our security group to allow SSH traffic on port `22` and HTTP traffic on port `80`. Now that our load balancer is expecting to handle traffic on port `443`, we need to update our security group to allow that traffic.

# Update Security Group to Allow Traffic on Port 443

Click on "Security Groups" in the EC2 service sidebar. Find the security group used by your ALB and select it. Then, click on "Edit inbound rules."

When all is said and done, we should have one rule for SSH traffic on port `22`, two rules for HTTP traffic on port `80` (one for "anywhere-IPv4" and one for "anywhere-IPv6"), and two rules for HTTP traffic on port `443` (one for "anywhere-IPv4" and one for "anywhere-IPv6"). It's these last two that we need to add.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/enyc9d32oqij18saw63x.png)

Click on "Save rules."

Now, your ALB can receive traffic on port `443`, sending that traffic to the target group with your EC2 instance.

# Update Hosted Zone to Route Custom Domain Traffic to ALB

For our very last step, we need to add some records to our hosted zone at Route 53. We need to let domain management know that requests to our subdomain (the one we requested the SSL certificate for) should be routed to our load balancer.

Navigate to the Route 53 service. Find your hosted zone, and then click on "Create record." Go ahead and click on "Switch to wizard." For routing policy, choose "Simple routing."

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d3lg4x0d2am1mo7dr8wt.png)

Next, we'll see a list of records to define. It's empty. Click on "Define simple record."

Enter your subdomain for the "Record name." We will create an `A` record that is an "Alias to Application and Classic Load Balancer." We choose the region where our ALB resides, and then we choose our ALB from the drop-down list.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6d7ft230rotz6kjqvtv9.png)

We click on "Define simple record" to finalize. Our list of records to create now has a single `A` record.

Click again on "Define simple record" at the top of the list, and perform all of the same steps as above, but this time for a `AAAA` record type. Once that's done, your list should look like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jfrj9emreewfc6w3650v.png)

Click on "Create records" to finalize.

# Test an HTTPS Request

Everything is in place. Finally... we can test it out by sending a curl request with HTTPS to our custom domain:

```bash
$ curl -i https://node-server-demo.codingplus.coffee
HTTP/2 200 
date: Mon, 22 Nov 2021 05:48:30 GMT
content-type: text/html; charset=utf-8
content-length: 12
x-powered-by: Express
etag: W/"c-5E8zZAGdGKFRyrcHK1pAu1s+J08"

Hello world.
```

It works! A quick check in the browser shows a secure connection, and we can even see our SSL certificate issued by Amazon.

# Conclusion

That might feel like a lot of steps just to get HTTPS. As I mentioned above, the steps are not few, but they _are_ straightforward. For spinning up our server in a Docker container, we could have used another service like AWS ECS or AWS CloudFormation, which might handle some of these manual steps for you. However, by manually going through the steps here, we see all of the individual pieces and configurations that need to be set up and connected together. It's a good process to go through for learning.

We did it! After walking together through the previous post and this one, we have accomplished the following:

* Containerized a Node.js Express server
* Pushed the container image to ECR
* Launched and configured an EC2 instance to run that container
* Configured the network to allow HTTP requests to our EC2 instance (and subsequently, to our server)
* Used Route 53 and Certificate Manager to set up a custom domain and provision an SSL certificate
* Created a target group and an application load balancer
* Configured our load balancer to forward HTTPS traffic to our EC2 instance

That's a pretty strong set of accomplishments. Well done!

###### Cover image Photo by [戸山 神奈](https://unsplash.com/@toyamakanna?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/wax-seal?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)