How To Secure Apache with mod_md Let’s Encrypt on Ubuntu 20.04 LTS

How do I secure Apache with mod_md Let’s Encrypt on Ubuntu 20.04 and obtain a free TLS/SSL certificate? How do I secure Apache 2 with Let’s Encrypt on Ubuntu 20.04 LTS server?

Apache server comes with a module named mod_md. We can use this for certificate provisioning via the ACME protocol. This page explains how to install, set up and configure Apache with a mod_md module to secure traffic with Let’s Encrypt free TLS/SSL certificate on Ubuntu 20.04 LTS server.
Tutorial requirements
Operating system/appUbuntu Linux with Apache 2
Root privileges required Yes
Difficulty Easy (rss)
Estimated completion time 15m
Table of contents


How to Secure Apache with mod_md Let’s Encrypt on Ubuntu 20.04

Let’s Encrypt is a CA that follows the ACME protocol. One can use Let’s Encrypt to issue free TLS/SSL certificates for Apache, Nginx, and other servers. In this tutorial, you will use mod_md to obtain a free TLS/SSL certificate for Apache 2 on Ubuntu 20.4 and set up your certificate to renew automatically too. Our sample set up is as follows:

  • Domain –
  • HTTPS port – 443
  • Virtual domain config file – /etc/apache2/sites-available/

Make sure Apache installed by following How to install Apache on Ubuntu 20.04 guide.

Step 1 – Installing mod_md for Let’s Encrypt

First, apply updates using the apt command:
sudo apt update
sudo apt upgrade

Then, install the mod_md by typing the following command:
sudo apt install libapache2-mod-md
Install Apache with mod_md Let's Encrypt on Ubuntu Linux 20.04 LTS

Enabling mod_md on Ubuntu 20.04 LTS

Turn on mod_md, type:
sudo a2enmod md
Sample outputs:

Enabling module md.
To activate the new configuration, you need to run:
  systemctl restart apache2

Make sure you activate the mod_ssl too, run:
sudo a2enmod ssl

Considering dependency setenvif for ssl:
Module setenvif already enabled
Considering dependency mime for ssl:
Module mime already enabled
Considering dependency socache_shmcb for ssl:
Enabling module socache_shmcb.
Enabling module ssl.
See /usr/share/doc/apache2/README.Debian.gz on how to configure SSL and create self-signed certificates.
To activate the new configuration, you need to run:
  systemctl restart apache2

Apache 2 must be reloaded or restarted with the help of the systemctl command”
sudo systemctl reload apache2.service

Step 2 – Set up the SSL certificate

Make sure your Apache 2 is working and listens on port 80. Verify using the ss command or netstat command:
sudo netstat -tulpn | grep ':80'
## or ##
sudo ss -tulpn | grep ':80'

Sample outputs:

tcp    LISTEN  0       128                        *:80                  *:*      users:(("apache2",pid=2550,fd=4),("apache2",pid=2549,fd=4),("apache2",pid=2548,fd=4))

All clients must connect to your server over port 80. Otherwise, you will not get validated for Let’s Encrypt certificate. From your desktop, run:
curl -I
curl command outputs validting that we can connect to the port TCP port 80:

HTTP/1.1 200 OK
Date: Wed, 06 May 2020 19:30:43 GMT
Server: Apache/2.4.41 (Ubuntu)
Last-Modified: Wed, 06 May 2020 19:15:29 GMT
ETag: "15e-5a4ff965902a3"
Accept-Ranges: bytes
Content-Length: 350
Vary: Accept-Encoding
Connection: close
Content-Type: text/html

Let us edit the /etc/apache2/sites-available/, enter:
sudo nano /etc/apache2/sites-available/
At the top of file add the following three mod_md directives:

## Secure Apache with mod_md Let's Encrypt directives ##
MDCertificateAgreement accepted
MDPrivateKeys RSA 4096


  • ServerAdmin : mod_md will use this email address when registering your domains at Let’s Encrypt.
  • MDCertificateAgreement accepted : You must accept the Terms of Service conditions as set by Let’s Encrypt.
  • MDomain : Declare a domain named that should be manged by mod_md to issue and renew certificates. You can use full domain name such as or or Make sure it matches to ServerName.
  • MDPrivateKeys RSA 4096 : Set type and size of the private keys generated.

Here is my complete config file :

## Apache with mod_md Let's Encrypt ##
## mod_md config for Let's Encrypt ##
MDCertificateAgreement accepted
MDPrivateKeys RSA 4096
## HTTP port 80 config ##
<VirtualHost *:80>
    DocumentRoot /home/
    DirectoryIndex index.html
    ErrorLog ${APACHE_LOG_DIR}/
    CustomLog ${APACHE_LOG_DIR}/ combined
    # Redirect all http requests to HTTPS (uncomment the following two lines when HTTPS issued) 
    # RewriteEngine On
    # RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
## HTTPS Config ##
<VirtualHost *:443>
    SSLEngine on
    DocumentRoot /home/
    DirectoryIndex index.html
    ErrorLog ${APACHE_LOG_DIR}/
    CustomLog ${APACHE_LOG_DIR}/ combined
    # Turn on HTTP/2 
    Protocols h2 http/1.1
    # Set HTTP Strict Transport Security
    Header always set Strict-Transport-Security "max-age=63072000"
## Only enable TLS v1.3 and avoid older protocols ##
SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1 -TLSv1.2
SSLHonorCipherOrder     off
SSLSessionTickets       off
## Turn on OCSP Stapling ##
SSLUseStapling On
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
## Permission for our DocumentRoot  ##
<Directory /home/>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted

Turn on Apache’s mod_rewrite and mod_headers under Ubuntu

We have already declared a rewrite rule in our config, so we need mod_rewrite. Hence, type the following command:
sudo a2enmod rewrite
Enabling module rewrite.
To activate the new configuration, you need to run:
systemctl restart apache2

Turn on mod_headers too:
sudo a2enmod headers
Enabling module headers.
To activate the new configuration, you need to run:
systemctl restart apache2

Check for config errors, run:

sudo apache2ctl configtest
Syntax OK

Step 3 – Open HTTPS (TCP port 443) using the UFW firewall on Ubuntu

Run the following ufw command to open TCP port 443 for everyone:
sudo ufw allow 443/tcp comment 'accept secure Apache connections'
Verify it rules:
sudo ufw status
See “How To Configure Firewall with UFW on Ubuntu 20.04 LTS” for more info.

Step 4 – Obtaining an SSL certificate using mod_md

So far, we installed mod_md for Apache on Ubuntu, turned on all essential modules, and open required TCP ports using a firewall. It is time to restart our Apache 2 server to obtain the free TLS/SSL certificate using Let’s Encrypt certificate authority (CA). Therefore, restart the Apache 2 server:
sudo systemctl restart apache2.service
As soon as Apache 2 restarted mod_md will contact Let’s Encrypt and request a certificate for your domain. Typically it takes up to one minute. You can check the server error log or Apache’s mod_status page to see if the request was successful or not. Here is what you will see in erro.log file:
sudo tail -f /var/log/apache2/error.log
One can use the grep command too:
sudo grep 'The Managed Domain' /var/log/apache2/error.log
Sample outputs indicating that LE has issued us a free TLS/SSL certificate:

[Wed May 06 20:17:38.112849 2020] [md:notice] [pid 21777:tid 139807872861952] AH10059: The Managed Domain has been setup and changes will be activated on next (graceful) server restart.

Of course we can visit server-status url too. For example:

Managed Domain Status for Apache with mod_md Let's Encrypt

Click to enlarge

A graceful Apache 2 server restart now is recommended to activate the certificate:
sudo systemctl reload apache2.service

Step 5 – Test secure Apache 2 connection

All you have to do is type the following command or use a web browser such as Firefox/Chrome to make sure you are getting HTTPS connection:
curl -I

mod_md status

curl command in action verify that our HTTPS connection is working and traffic is secured and encrypted

Here is outputs from SSL Lab’s test:
How To Secure Apache with Let's Encrypt on Ubuntu 20.04 LTS

My secure Apache server with Let’s Encrypt TLS/SSL running on Ubuntu 20.04 LTS and verified by SSL Lab’s test

Step 6 – Automatically renewing an SSL certificate using mod_md and watchdog_module

The mod_md uses mod_watchdog module, which provides programmatic hooks for other modules to run tasks such as renewing TLS/SSL certificates and more periodically. In other words, auto-renew mode requires mod_watchdog to be active in your server. Hence, verify that mod_watchdog is activated using the following command:
sudo apache2ctl -M
sudo apache2ctl -M | grep mod_watchdog

Loaded Modules:

 core_module (static)
 so_module (static)
 watchdog_module (static)
 http_module (static)
 unixd_module (static)
 access_compat_module (shared)
 alias_module (shared)
 auth_basic_module (shared)
 authn_core_module (shared)
 ssl_module (shared)
 status_module (shared)

Step 7 – Monitoring certificate status

Now we set up Apache with mod_md and got a free TLS/SSL from Let’s Encrypt. It is time to monitor status of our certificate. There are two ways. First open /server-status URL:

Managed Domains Apache Status

Click to enlarge

Edit your server config file, run:
sudo nano /etc/apache2/sites-available/
Append the following:

<Location "/md-status">
  SetHandler md-status

Save and close the file. Restart the server and run:
sudo systemctl restart apache2.service

Sample outputs:

  "version": "2.0.10",
  "managed-domains": [
      "name": "",
      "domains": [
      "contacts": [
      "transitive": 1,
      "ca": {
        "proto": "ACME",
        "url": "",
        "agreement": "accepted"
      "state": 2,
      "renew-mode": 1,
      "renew-window": "33%",
      "warn-window": "10%",
      "must-staple": false,
      "cert": {
        "valid-from": "Wed, 06 May 2020 19:17:37 GMT",
        "valid-until": "Tue, 04 Aug 2020 19:17:37 GMT",
        "serial": "040E339A0A7D2224819A550BBB4596279F67",
        "sha256-fingerprint": "d78933fa946cb71810111876049defa4feb6820c319c69918ba925b463bbd11c"
      "renew": false


In this tutorial, you learned how to secure Apache with mod_md Let’s Encrypt module to issue and auto-renew free TLS/SSL certificate on Ubuntu 20.04 LTS Linux server. For more information, see mod_md documentation here. Keep reading read of the series:

This entry is 2 of 2 in the Linux, Apache, MySQL, PHP (LAMP) stack on Ubuntu 20.04 Tutorial series. Keep reading the rest of the series:
  1. How to install Apache on Ubuntu 20.04 LTS
  2. Secure Apache with mod_md Let’s Encrypt on Ubuntu 20.04 LTS

🐧 If you liked this page, please support my work on Patreon or with a donation.
🐧 Get the latest tutorials on SysAdmin, Linux/Unix, Open Source/DevOps topics:
CategoryList of Unix and Linux commands
File Managementcat
FirewallAlpine Awall CentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network Utilitiesdig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNAlpine CentOS 8 Debian 10 Firewall Ubuntu 20.04

6 comments… add one
  • Sima Chavda Aug 12, 2020 @ 9:09

    I am getting the following error when installing Let’s Encrypt SSL on my domain:

    Waiting for verification…
    Challenge failed for domain
    dns-01 challenge for
    Cleaning up challenges
    Some challenges have failed.

    • 🐧 Vivek Gite Aug 12, 2020 @ 11:40

      Are you using dns challenge? This tutorial only works with http challenge.

  • Frederic Sep 4, 2020 @ 15:11

    Thanks a lot, and great tutorial, anyway I’m not sure to understand about the renew. I mean, is this automatic renw ? even without any crontab ?


    • 🐧 Vivek Gite Sep 4, 2020 @ 15:17

      yes, watchdog_module will do auto renewal. There is no cron job since Apache with watchdog_module always running on port 80 and 443.

      • Frederic Sep 6, 2020 @ 22:52

        Thanks Vivek !

  • Abigail Sep 7, 2020 @ 6:13


    I am working with a PHP app. This post was a lifesaver. One question, how can I get A+ score in the test? Anyone willing to share httpd.conf settings?

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre>, <code>...</code> and <kbd>...</kbd> for code samples.