A cheap way to use SSL certificates for custom domains on Amazon AWS

Rogério de Oliveira
11 min readSep 1, 2022

--

Credits: Love Lock Trees

Before we start

This article is suited for those who are looking for an alternative to deploy small apps on Amazon AWS utilizing a custom domain under HTTPS without paying a considerable value for that — usually, a consequence imposed by ELB — Elastic Load Balancer.

This content assumes you have some basic knowledge about AWS.

Motivation

Nowadays it is quite common to hear people discussing base cloud solutions for software applications, that are no longer seen as complex things, used by big companies for their large software solutions. It turns out the cloud has become so accessible in terms of complexity that with a few clicks, it is possible to set up a whole environment for your app depending on the provider you are in. It is fantastic! Who would have thought it’d be possible ten years ago? Many tools can automate the deployment process and even make moving across cloud providers something transparent (if you don’t know what I’m talking about, please take a look at Terraform or Morpheus for instance ). Well, welcome to the 2020s when this process becomes effortless, at least almost.

Regardless of our application size, we can try cloud-based services for free on different providers such as Microsoft Azure, Digital Ocean, Amazon AWS, among many others. It can be done by trial plans which can offer a good starting point to test the app remotely.

This article will approach one of the most famous among all those players: Amazon AWS. To be more specific, a scenario about small up to middle size solutions which, I believe would be more suitable for the idea that I will get across to you. The key point here is to do that without making a mint. For that, I am going to use a real scenario that I passed through when trying to decide where to deploy a middle-side back-end written in Node JS alongside a PostgreSQL container at a minimum price in a dedicated machine.

In a short, for this solution the requirements/assumptions are the following:

1 — Full control over the environment;

2 — Free SSL certificate;

3 — Cheap as possible assuming the last 2 requirements.

With that in mind, let’s discuss some underlying questions involving those requirements.

Requirement 1 — Shared vs dedicated instances

The first point is about what machine type we will choose: private or shared. Overall, shared instances tend to be cheaper than dedicated ones and they have a critical downside, their control is limited. Generally, shared instances don’t allow us to take on full control over their environment, some commands might be blocked by the service provider. Going over our requirements, it definitely doesn’t fit with the first one. On the other hand, dedicated instances usually may have considerable costs when compared to their shared counterparts. On AWS it’s not an exception, an standard EC2 machine can be more expensive than some shared services available out there. Even so, personally I believe it’s worth it because we’re going to have a whole environment without any limitations about what we can run and how to do it.

Requirement 2 — The “problem” of getting the free AWS SSL certificate

Amazon provides the “free” AWS SSL for custom domains, although the only way to use it is to deploy the cert on the ELB entity (Elastic Load Balancing) that means it is required to attach the ELB to the EC2 machine. The problem is ELB service has a considerable share of the costs, so this condition imposed by Amazon doesn’t fit with our context at all. For small or even middle-size apps, setting up an ELB service can be a total waste of cash. Actually, this service is charged even when it is not in use — in idle mode. Besides, there’s no sense scaling up a load balancer for an app that can run pretty well in a single instance, thus to keep on with the initial idea, some way out needs to be found.

Figure 1 — The standard way to use a custom domain on Amazon AWS.

A good alternative would be to use some free SSL cert avoiding the load balancer which could help us to save money. Here is the point where Let’s Encrypt comes into play. More on that in the next topic.

Requirement 3 — How did I reach up the cheapest alternative?

After digging up tons of info on the internet, mixing some principles, strategies and tips, I ended up with a solution: Let’s encrypt as an alternative to AWS SSL cert. In a nutshell, Let’s Encrypt is a non-profit certificate authority run by Internet Security Research Group that provides X.509 certificates for free.
To make this goal come true, it’s necessary to set up a proxy where the SSL cert will be deployed as shown in Figure 2. For my scenario I choose Nginx for that, although be free to choose the web server that fits better in your context. I’m used to Nginx stuff, so it looked fine to me. It could have been Caddy or Envoy for instance. By the way, Caddy is an appealing case because it uses HTTPS automatically and by default connects to Let’s Encrypt.

Figure 2— Nginx as a proxy server.

Well, at this point we have scaffolded the solution to run a server over HTTPS on AWS without spending a lot of money. Enough of theory, let’s make all that work.

Getting the hands dirty

Gathering up all insights, the final solution is the following:

Figure 2 — Let’s Encrypt can be a good alternative to the default Amazon SSL certificate. This structure can help save money when a single EC2 instance is enough.

Easy peasy, isn’t it? The idea is composed of four steps which will be explained one by one. Notice that, this time we moved the SSL cert to the EC2 instance instead of the ELB, thus we can cut it off from the solution.

Important note: The article’s goal is to teach how to carry out the process of getting a SSL certificate to establish communication between the server and its clients. If you want to use S3 + CloudFront to deliver your website (a common scenario for single-page applications) over a custom domain, you also need to configure the Cloud Front SSL cert. Luckily, there’s no extra charge for using that cert which is free. For further information on how to accomplish that, please check out the related Amazon doc.

01 Make Let’s Encrypt your cert issuer

In this step, you are going to hook up your domain to the public EC2 DNS and certify Let’s Encrypt as a cert issuer for that domain.

Regardless of the domain provider chosen, it can be done by creating a new CNAME — Canonical Name record on your provider, linking it with the public EC2 DNS. The example shown ahead was based on Hostinger as the domain provider, yet the configs are somewhat similar among them. Even so, I recommend checking this part directly with your provider.

Table 1 — Associating the EC2 public IP to the domain obtained on Hostinger.

Afterward, you need to create an A record that translates the human-readable domain name “your-domain.com” to an IP address. At this point, the main domain alongside its variations (subdomains), needs to be registered, then it could look like this:

Table 2 — Associating the main domain and its subdomains to the public EC2 IPv4 on Hostinger.

Finally, it is time to associate Let’s Encrypt as a certificate issuer for your domain. So that it’s necessary to create a CAA — Certification Authority Authorization record utilized to specify which certificate authorities (CAs) are allowed to issue certificates for a domain.

Table 3 — Declaring Let’s encrypt as a certificate issuer for the domain on Hostinger.

For instance, If you were using some SSL cert from Amazon, it would be necessary to fill up the above table with Amazon CAs instead of Let’s Encrypt. Now that you have finished the domain setup, it is time to move on to the next step.

02 Installing Certbot

Getting an SSL cert from Let’s Encrypt servers is relatively simple and Certbot is the element that allows us to achieve this goal. According to its doc, Certbot is described as a tool intended for obtaining certs from Let’s Encrypt and (optionally) auto-enable HTTPS on your server. In other words, it automates the whole process of getting and deploying a cert from Let’s Encrypt. Indeed, the Let’s Encrypt team recommended this tool.

Installing Certbot will vary according to the operating system on which your server is running over. Here will be explained how to install it for Amazon Linux 2 which I believe to be the most common for the context we are talking about. Typically, the following commands are required:

1 — Enable EPEL repository (extra packages for Enterprise Linux).

2 — Install Certbot.

3 — Install Certbot plugin for Nginx.

The plugin installed in the last step is responsible for connecting Nginx to the Let’s Encrypt service and automatizing the tasks related to getting and deploying the SSL cert into Nginx.

From now on, if everything is okay, you already have all about Certbot installed on your server.

03 Getting Nginx ready

This step consists in adjusting Nginx to work with Certbot. Here, it assumes you already have installed Nginx on your server, but if you don’t, usually typing the command below is enough:

According to Figure 2, all incoming HTTP requests on port 80 must pass through Nginx (the proxy) instead of reaching the server directly. In addition, it’s necessary to associate the domain used by the clients with Nginx. To achieve this behavior, a configuration file needs to be created in the directory /etc/nginx/conf.d which will route the external requests from port 80 to the Nginx server. The file name needs to exactly match the domain name. Assuming our fictitious domain “your-domain.com”, the file’s name would be your-domain.com.conf, and its content as follows:

The created file is known as a server block for a website. There are some directives in this block worthy to take a look at:

Listen: tells Nginx the hostname/IP and the TCP port where it should listen for HTTP connections.

Server name: allows multiple domains to be served from a single IP address. Ideally, it should be created per domain or site. Based on the request header it receives, the server decides which domain to serve. The example above is set up for serving requests from your-domain.com and www.your-domain.com. Besides, in the case of some domain variants, they also need to be mapped within this file. For more info about how to configure subdomains for Nginx take a look at this article: How to Configure NGINX.

Save the file and load the new configuration by restarting Nginx utilizing the following statement:

Last but not least, Nginx needs to be adjusted to operate as a reverse proxy as described in Figure 2hence, all incoming requests will be mapped to the server which is running over some local host port.

That’s everything we need about Nginx’s configuration.

04 Getting and deploying the SSL cert

We reached the last big step. Here we need to run the Certbot plugin that will connect to the Let’s Encrypt server to take and deploy the aimed cert. For this purpose, the following command comes to play:

In this command, we pass the main domain alongside its variants if they exist. By doing that, Certbot edits the Nginx configuration automatically to serve the obtained cert, turning on HTTPS access in a single step. Yet, if you’re feeling more conservative and would like to make the changes to your Nginx configuration by hand use this command:

If you choose the first way, respond to prompts from Certbot to configure the HTTPS settings, which involves entering your email address and agreeing to the Let’s Encrypt terms of service.

When the certificate generation is done, Nginx reloads with the new settings and Certbot will show up a message indicating that the process was successful as well as specifying the certificate file location in your server.

Now you have got and deployed an SSL cert through the structure shown in Figure 2. All four steps are relatively simple, but they need to be carried on thoroughly to succeed. To confirm that your site is set up properly, visit https://your-domain.com/ in your browser and look for the lock icon in the URL bar.

Everything should be okay so far and you would be able to start your client-server system over HTTPS, although there is a big but: by default Let’s Encrypt certificates expire after 90 days. It means you need to rerun this step before the cert expires manually which may not be a good deal. Since the cert is expired, the server will stop responding to the clients due to an invalid cert error. To get rid of this undesired manual process, let’s figure out how we could automate it in the next section.

05 Bonus —Automatization

Certbot comes with a cron job or systemd timer that will renew your certificates automatically before they expire, so you will not need to run Certbot again unless you change your configuration. To test the automatic renew, run this command:

If for some reason, the automatic renewal does not work, you can create a cron file to do that explicitly.

1 — Open the contrab file with: $ crontab -e
2 — Add Certbot command to run daily. In this example, it will run every day at noon:

0 12 * * * /usr/bin/certbot renew — quiet

The command above checks if the certificate hosted by the server will expire within the next 30 days, and renew it if so. The — quiet directive tells Certbot not to generate any output during the process.

Conclusion

By following these four steps you could check how to run your website over HTTPS without signing up for the ELB service. As mentioned before, it can be pretty handy for small systems or even for prototyping. Most of the content approached here can be found in more detail on Certbot official page and Nginx official page. I believe the ace in the hole here was about unifying everything in a single and straight content. Usually, I encourage everyone to check out the official docs whichever the technology is in use, whether when a problem pops up or just to go higher. Finally, I hope this content can help you, or at least be a good starting point.

References

Linode. Hot to configure Nginx. Available at: <https://www.linode.com/docs/guides/how-to-configure-nginx/>. Accessed on July 10, 2022.

RAWDAT Amir. Using Free Let’s Encrypt SSL/TLS Certificates with Nginx. Available at: <https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/>. Accessed on June 15, 2022.

--

--

Rogério de Oliveira
Rogério de Oliveira

Written by Rogério de Oliveira

Postgraduate in Software Architecture - PUC/MG | Computer Engineering - UNIFEI My LinkedIn: https://www.linkedin.com/in/rogerio-oliveirahs/

Responses (1)