Install a Free Let's Encrypt TLS/SSL Certificate on a CentOS 7 LEMP Server with Certbot

Updated on April 19, 2021
Install a Free Let's Encrypt TLS/SSL Certificate on a CentOS 7 LEMP Server with Certbot header image

Introduction

Vultr's One-Click LEMP application is an easy-to-deploy solution for web development on Linux with Nginx, MySQL, and PHP. Let's Encrypt is a certificate authority that provides free TLS certificates. This tutorial helps you set up HTTPS for your website on a CentOS 7 One-Click LEMP server using a Let's Encrypt TLS certificate. After completing this tutorial, your website will serve pages over HTTPS and redirect all HTTP requests to HTTPS.

Prerequisites

  • You have deployed a CentOS 7 One-Click LEMP application server.
  • You have logged in as root via SSH.
  • You own a domain name and have complete control over it.

Replace the examples in this guide (example.com and 192.168.0.123) with your domain name and IP address.

1. Set Up DNS Records

This guide assumes your website's domain name is www.example.com, and you want to redirect your apex domain example.com to www.example.com.

Create two A records in your DNS: example.com and www.example.com. Set both records to resolve to the IP address of your CentOS server.

See instructions for Vultr DNS, or refer to the documentation for your DNS host.

2. Install Certbot

Certbot is a free, open-source software tool for getting and renewing automatically Let's Encrypt certificates. The strongly recommended method for installing Certbot is using Snap Store, the app store for Linux with millions of users. The Certbot snap makes it easy to get the latest Certbot version with features like automatic certificate renewal.

Install snapd

  1. Update the CentOS system:

     # yum update -y
  2. Install the snapd package:

     # yum install snapd -y
  3. Enable the snapd service:

     # systemctl enable --now snapd.socket
  4. Enable classic snap support:

     # ln -s /var/lib/snapd/snap /snap
  5. Log out and back in again to update snap's paths.

  6. Get the latest version of snapd core:

     # snap install core; snap refresh core

    If you get this error:

     error: too early for operation, device not yet seeded or device model not acknowledged

    Don't worry. After installing snapd, it may take a little while to initialize its environment. You have to wait a while before rerunning the above command.

Install Certbot

Install with Snap.

# snap install --classic certbot

Make the certbot command globally available.

# ln -s /snap/bin/certbot /usr/bin/certbot

3. Get a Let's Encrypt Certificate

When you run the certbot command to get a certificate from Let's Encrypt, their servers need to verify that you control the domain names in that certificate using a method call HTTP-01 challenge. Let's Encrypt gives a token to certbot, and certbot puts a file on your web server at http://www.example.com/.well-known/acme-challenge/<TOKEN>. You must prepare Nginx to respond to that link.

  1. Rename the /etc/nginx/conf.d/http.conf file for later use if needed:

     # mv /etc/nginx/conf.d/http.conf /etc/nginx/conf.d/http.conf.default
  2. Create the new /etc/nginx/conf.d/http.conf file:

     # nano /etc/nginx/conf.d/http.conf
  3. Paste the following contents:

     server {
         listen 80;
    
         server_name www.example.com example.com;
    
         root /usr/share/nginx/html;
    
         location / {
             return 301 https://www.example.com$request_uri;
         }
    
         location /.well-known/acme-challenge/ {}
     }

    This configuration makes Nginx redirect all HTTP requests, except those from Let's Encrypt, to corresponding HTTPS requests.

  4. Save and exit the file. Then check the Nginx configuration:

     # nginx -t
  5. Apply the new configuration.

     # systemctl reload nginx.service
  6. Get the certificate from Let's Encrypt.

     # certbot certonly --webroot -w /usr/share/nginx/html -d example.com -d www.example.com -m admin@example.com --agree-tos

    Here are descriptions of the command options:

    • certonly: get a certificate without installing it. You will install it manually using the recommended configuration from Mozilla in the next step.
    • --webroot: the authentication method (place files in a server's webroot folder for authentication.)
    • -d example.com -d www.example.com: get a multiple domain name certificate. You may use up to 100 -d domain entries.
    • -w /usr/share/nginx/html: specify the webroot folder of the above domain names, as declared with the root directive in the /etc/nginx/conf.d/http.conf file.
    • -m admin@example.com: the notification email address for this certificate.
    • --agree-tos: agree to the terms of service.

    When done, certbot tells you the path of your certificate file and key file:

     /etc/letsencrypt/live/example.com/fullchain.pem
     /etc/letsencrypt/live/example.com/privkey.pem

    Another critical file, located in the same folder, is chain.pem. It is also essential for the next step.

4. Set Up HTTPS

Mozilla, a reputable organization, maintains three recommended configurations for servers using TLS, which correspond to three levels of browser compatibility. This tutorial adapts from the Intermediate configuration because it is suitable for a general-purpose server with many types of clients (Firefox 27, Android 4.4.2, Chrome 31, Edge, IE 11 on Windows 7, Java 8u31, OpenSSL 1.0.1, Opera 20, Safari 9, and above.)

  1. Generate a file with DH parameters for DHE ciphers:

     # openssl dhparam -out /etc/nginx/dhparam.pem 2048

    2048 is the size of DH parameters. This process may take a while, so please be patient.

  2. Back up the /etc/nginx/conf.d/https.conf file for later use if needed:

     # cp /etc/nginx/conf.d/https.conf /etc/nginx/conf.d/https.conf.default
  3. Open the /etc/nginx/conf.d/https.conf file:

     # nano /etc/nginx/conf.d/https.conf
  4. Find the following lines:

     listen 443 ssl default_server;
     server_name _;
    
     ssl_certificate /etc/nginx/ssl/server.crt;
     ssl_certificate_key /etc/nginx/ssl/server.key;

    Replace them with:

     listen 443 ssl http2;
     listen [::]:443 ssl http2;
    
     server_name www.example.com;
    
     ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
     ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
     ssl_session_timeout 1d;
     ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    
     # DH parameters file
     ssl_dhparam /etc/nginx/dhparam.pem;
    
     # intermediate configuration
     ssl_protocols TLSv1.2;
     ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
     ssl_prefer_server_ciphers off;
    
     # HSTS (ngx_http_headers_module is required) (63072000 seconds)
     #
     # Uncomment the following line only if your website fully supports HTTPS
     # and you have no intention of going back to HTTP, otherwise, it will
     # break your site.
     #
     # add_header Strict-Transport-Security "max-age=63072000" always;
    
     # OCSP stapling
     ssl_stapling on;
     ssl_stapling_verify on;
    
     # verify chain of trust of OCSP response using Root CA and Intermediate certs
     ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    
     # Use Cloudflare DNS resolver
     resolver 1.1.1.1;

    The above configuration is for the domain name www.example.com. It enhances the performance and security of your website with:

  5. To redirect HTTPS requests from example.com to www.example.com, add the following server block at the top of the file:

     server {
             listen 443 ssl;
             listen [::]:443 ssl;
    
             server_name example.com;
    
             ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
             ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    
             return 301 https://www.example.com$request_uri;
     }

    For redirection, a simple server block like the above is enough.

  6. Save and exit the file. Then check the Nginx configuration:

     # nginx -t
  7. Apply the new configuration:

     # systemctl reload nginx.service

5. Automate Renewal

Let's Encrypt certificates are valid for 90 days, so you must renew your certificate at least once every three months. The Certbot installation automatically created a systemd timer unit to automate this task. Run the following command to verify the timer is active:

# systemctl list-timers | grep 'certbot\|ACTIVATES'

After renewing the certificate, Certbot will not automatically reload Nginx, so Nginx still uses the old certificate. You must write a script inside the /etc/letsencrypt/renewal-hooks/deploy folder to reload Nginx.

  1. Open your text editor:

     # nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
  2. Paste the following contents into the editor:

     #!/bin/bash
    
     /usr/bin/systemctl reload nginx.service
  3. Save and exit. Then make the script executable:

     # chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Test the renewal process with a dry run.

# certbot renew --dry-run

This update requires communication on port 80. Make sure not to close this port in your firewall.

6. Test HTTPS

  1. Restart the server to make sure it still works after a reboot:

     # reboot
  2. Open your browser and access your website using the domain example.com or www.example.com. The browser should redirect you to the domain www.example.com over the HTTPS protocol.

  3. Test with SSL Labs. Open the https://www.ssllabs.com/ssltest/ link in your browser. Then enter the domain name www.example.com into the Hostname text box, and click Submit. The test may take a few minutes. When it finishes, you should get an A.

References