Secure Apache with Let's Encrypt on Ubuntu 20.04

Let’s Encrypt is a Certificate Authority (CA) that facilitates obtaining and installing free TLS/SSL certificates, thereby enabling encrypted HTTPS on web servers. It simplifies the process by providing a software client, Certbot, that attempts to automate most (if not all) of the required steps. Currently, the entire process of obtaining and installing a certificate is fully automated on both Apache and Nginx.

In this guide, we’ll use Certbot to obtain a free SSL certificate for Apache on Ubuntu 20.04, and make sure this certificate is set up to renew automatically.

This tutorial uses a separate virtual host file instead of Apache’s default configuration file for setting up the website that will be secured by Let’s Encrypt. We recommend creating new Apache virtual host files for each domain hosted in a server, because it helps to avoid common mistakes and maintains the default configuration files as a fallback setup.
inspired by the document of Digitalocean.

Prerequisites

  1. Creat your domain in Digitalocean Control Panel and direct to your Server IP.
  2. Apache aready installed:
sudo apt install apache2
  1. Be sure that you have a virtual host file for your domain, something like /etc/apache2/sites-available/your_domain.conf

Step 1: Checking Apache Virtual Host Configuration

Find the existing ServerName and ServerAlias lines. They should look like this:

...
ServerName your_domain
ServerAlias www.your_domain
...

Step 2: Install Certbot

sudo apt install certbot python3-certbot-apache

Save and quit editor when you are down. Then run the following command to validate changes:

sudo apache2ctl configtest

You should get a Syntax OK as a response. If you get an error, reopen the virtual host file and check for any typos or missing characters. Once your configuration file’s syntax is correct, reload Apache so that the changes take effect:

sudo systemctl reload apache2

With this change, cerbot can find the correct VirtualHost block and update it.

Step 3 — Allowing HTTPS Through the Firewall

Once you have activated the UFW firewall, as suggested, you'd need to adjust the settings to allow HTTPS traffic. By leveraging the Apache Full profile it allows both HTTP and HTTPS traffic on your server.

sudo ufw allow 'Apache Full'
sudo ufw delete allow 'Apache'

Then your status will now similar to this:

Apache Full                ALLOW       Anywhere                  
80/tcp                     ALLOW       Anywhere                  
443/tcp                    ALLOW       Anywhere                  
21/tcp                     ALLOW       Anywhere                  
20/tcp                     ALLOW       Anywhere                  
4040                       ALLOW       Anywhere                  
22                         ALLOW       Anywhere                  
666                        ALLOW       Anywhere                  
22/tcp (v6)                ALLOW       Anywhere (v6)             
Apache Full (v6)           ALLOW       Anywhere (v6) 

Now we can continue to run Certbot and obtain your certificates.

Step 4 — Obtaining your SSL Certificate

Certbot offers a variety of ways to obtain SSL certificates using plugins. The Apache plugin will take care of reconfiguring Apache and reloading the configuration whenever necessary. To use this plugin, type the following:

sudo certbot --apache

This script will prompt you to answer a series of questions in order to configure your SSL certificate. First, it will ask you for a valid e-mail address. This email will be used for renewal notifications and security notices.

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator apache, Installer apache
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): you@your_domain

There are several options you need to choose. Set up your choice to finish the procee then you will get ssl certificate of your domain, congratulations!

Step 5 — Verifying Certbot Auto-Renewal

Let’s Encrypt certificates are only valid for ninety days. This is to encourage users to automate their certificate renewal process and ensure that misused certificates or stolen keys will expire sooner than later.

The certbot package you installed takes care of renewals by including a renew script to /etc/cron.d, which is managed by a systemctl service called certbot.timer. This script runs twice a day and will automatically renew any certificate that’s within thirty days of expiration.

Check the status of this service and make sure it’s active and running:

sudo systemctl status certbot.timer

The output should like following:

● certbot.timer - Run certbot twice daily
     Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Sat 2022-01-29 15:08:04 UTC; 1 months 23 days ago
    Trigger: Thu 2022-03-24 22:22:45 UTC; 10h left
   Triggers: ● certbot.service

Test the renew process by doing a dry run with cerbot:

sudo certbot renew --dry-run

If you receive no errors, you’re all set. When necessary, Certbot will renew your certificates and reload Apache to pick up the changes. If the automated renewal process ever fails, Let’s Encrypt will send a message to the email you specified, warning you when your certificate is about to expire.

Some Issues

When you run the last set up of your cerbot-letsencrypt process, the error occurred like:

#OUTPUT
An unexpected error occurred:
AttributeError: module 'lib' has no attribute 'X509_get_notAfter'
Please see the logfiles in /var/log/letsencrypt for more details.

It caused by the current version of python and pyOpenSSL mainly for that the system does not correspond, and with the version of cerbot, cryptography.
Someone suggest to run the commands below:

pip uninstall pyOpenSSL
pip install pyOpenSSL

or

apt remove python3-openssl -y 
apt autoremove

Made sure that/usr/local/lib/python3.5/dist-packages/OpenSSL/SSL.py was removed.

apt install python3-openssl -y

BUT these above still do not work with my case. Finaly I found a very naive solution:

sudo python -m easy_install --upgrade pyOpenSSL

Explaination:
Upgrading pyopenssl with pip was not working as none of the commands related to to pip was working for me. By upgrading pyopenssl with easy_install, above problem can be solved.