Setting up SSL Certificates for HAProxy with Let’s Encrypt
Tags: security, loadbalancing, haproxy, devops
Published: 2023-04-08 21:54:06

In this tutorial, I’ll be sharing how I configured my HolbertonBnB web servers at ALX with [Let’s Encrypt](https://letsencrypt.org/) and [HAproxy](https://www.haproxy.com/) SSL termination.

Let’s Encrypt is a new Certificate Authority (CA) that offers an accessible way to acquire and install free TLS/SSL certificates for web servers, allowing secure communication through encrypted HTTPS. One of the tools offered by Let’s Encrypt is Certbot, a software client that streamlines the certificate acquisition and installation process.

## Prerequisites

Before following this tutorial, you’ll need to know/have a few things.
- [What is SSL?](https://www.cloudflare.com/learning/ssl/what-is-ssl/)

- [What is HTTPS?](https://en.wikipedia.org/wiki/HTTPS)

- [What is SSL Termination?](https://docs.digitalocean.com/glossary/ssl-termination/)

- Haproxy: This can be installed through various methods, but for this tutorial, we will be using the simple simple `apt-get install haproxy`.

> Secure Sockets Layer, SSL, is a protocol for establishing encrypted and authenticated links between networked computers in order to keep internet connections secure and to safeguard sensitive data.
> SSL termination reduces the load on your servers while speeding up and simplifying data exchanges. SSL termination allows your application to handle more connections at a time.

Also, you must own or control the registered domain name that you wish to use the certificate with.

Let’s move on to installing Certbot, the Let’s Encrypt client software, once you have completed all the prerequisites.

## Step 1: Install Certbot
The first step to obtaining an SSL/TLS certificate is to install Certbot software on your server. Let’s Encrypt’s client is now called [Certbot](https://github.com/certbot/certbot) which is used to generate the certificates. To get the latest code you either clone the repository Certbot or use apt-get:

Using apt-get install, first, update the local package index:

```
$ sudo apt update
$ sudo apt install -y certbot python3-certbot-nginxbash
```

## Step 2 — Obtaining a Certificate
Diving in, the first thing you will require is a certificate. Let’s Encrypt offers multiple plugins to obtain SSL certificates, most of the plugins will only help you with obtaining a certificate that you must manually configure your web server to use.

These plugins are called “authenticators” because they authenticate whether a server should be issued a certificate, without installing it.

### Generating the certificate:

The Standalone plugin is a straightforward method for acquiring SSL certificates. It operates by launching a small web server (default on port 80) on your server, which Let’s Encrypt CA uses to verify your server’s identity and issue the certificate. However, to use this method, port 80 must be available.

Make sure that there is nothing listening on port 80. To list usage:

```
$ netstat -na | grep ':80.*LISTEN'
# Kill everything that might be on this port
$ sudo service haproxy stop
$ sudo certbot certonly --standalone -d www.example.com --non-interactive --agree-tos --email example@gmail.com
```


![If everything is successful, certbot will print an output message like this ⬆️ You will want to note the path and expiration date of your certificate, which was highlighted in the example output above.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wsb9e74wjlghuxvptcnn.png)

After obtaining the cert, you will have the following PEM-encoded files:

- cert.pem: Your domain’s certificate
- chain.pem: Let’s Encrypt chain certificate
- fullchain.pem: a combination of cert.pem and chain.pem
- privkey.pem: the private key to your certificate.

> The files themselves are placed in a subdirectory in /etc/letsencrypt/archive. However, Certbot creates symbolic links to the most recent certificate files in the /etc/letsencrypt/live/your_domain_name directory.

## Step 3: Configure HAProxy to Accept Encrypted Traffic
To configure HAProxy to accept encrypted traffic for your subdomain, follow these steps:

When setting up SSL termination with HAProxy, you need to combine fullchain.pem and privkey.pem into one file.

first, create the directory where the combined file will be placed, `/etc/haproxy/certs` :

```
$ sudo mkdir -p /etc/haproxy/certs
```

```
# Next, create the combined file with this cat command (substitute the highlighted example.com with your domain name):

$ DOMAIN='example.com' sudo -E bash -c 'cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/letsencrypt/live/$DOMAIN/privkey.pem > /etc/haproxy/certs/$DOMAIN.pem'
```

```
# Secure access to the combined file, which contains the private key, with this command:

$ sudo chmod -R go-rwx /etc/haproxy/certs
```

It will create a combined cert under `/etc/haproxy/certs/example.com.pem`

### Haproxy configuration
If haproxy happens to be running, stop it with service haproxy stop.

First, save the default configuration file: `cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.old`. 
Now, overwrite the old one with this new one (comments about what each setting does, are in-lined; they are safe to copy):

```
### Frontend Sections
frontend www-http
   bind *:80
   # Adds http header to end of end of the HTTP request
   reqadd X-Forwarded-Proto:\ http
   # Sets the default backend to use which is defined below with name 'www-backend'
   default_backend www-backend
```

```
# Add a frontend to handle incoming HTTPS connections
frontend www-https
    # Bind 443 with the generated letsencrypt cert.
    bind *:443 ssl crt /etc/haproxy/certs/domain.pem
    # set x-forward to https
    reqadd X-Forwarded-Proto:\ https
    # Select a Challenge
    acl letsencrypt-acl path_beg /.well-known/acme-challenge/
    # Use the challenge backend if the challenge is set
    use_backend letsencrypt-backend if letsencrypt-acl
    default_backend www-backend
```

### Backend Sections

```
backend www-backend
   # ssl_fc: Returns true when the front connection was made via an SSL/TLS transport
   redirect scheme https code 301 if !{ ssl_fc }
   server www-1 www_1_private_IP:80 check
   server www-2 www_2_private_IP:80 check

backend letsencrypt-backend
   # Lets encrypt backend server
   server letsencrypt 127.0.0.1:54321
```

Save this, and start haproxy with `sudo service haproxy restart`. If you did everything right, it should say nothing. Be sure to validate the config with `haproxy -c -f /etc/haproxy/haproxy.cfg `.

Also, ensure its running:
`$ sudo service haproxy status`

Once your server is started, you should be able to open up your website from a different browser, not on your local network, and see that it has a valid certificate installed. In Chrome, you should see a green icon telling you that the cert is valid.
And that is all. HAProxy is now using a free Let’s Encrypt TLS/SSL certificate to securely serve HTTPS traffic.
If you have any questions or encounter any issues during the setup process, please leave a comment below. Thank you for reading!

### Sources:
Helpful blog posts that inspired this article:

- [This post](https://skarlso.github.io/2017/02/15/how-to-https-with-hugo-letsencrypt-haproxy/) by Skarlso
- [This tutorial](https://www.digitalocean.com/community/tutorials/how-to-secure-haproxy-with-let-s-encrypt-on-ubuntu-14-04) by digital ocean

## [Boluwatife Oyewumi](https://github.com/Bolexzy)