HAProxy is a open-source TCP/HTTP load-balancing proxy server supporting native SSL, keep-alive, compression CLI, and other modern features.
Let’s Encrypt is a free, automated, and open certificate authority (CA), run for the public’s benefit. Let’s Encrypt is a service provided by the Internet Security Research Group (ISRG).
Let's Encrypt offers many options and plugins to create and validate certificate via its client.
If you’re running a local webserver for which you have the ability to modify the content being served, and you’d prefer not to stop the webserver during the certificate issuance process, you can use the webroot plugin to obtain a cert by including certonly and --webroot
on the command line. In addition, you’ll need to specify --webroot-path
or -w
with the top-level directory (“web root”) containing the files served by your webserver. For example, --webroot-path /var/www/html
or --webroot-path /usr/share/nginx/html
are two common webroot paths.
Read more about this option here https://certbot.eff.org/docs/using.html#webroot
In our production environment we have the following setup, HAProxy will handle all HTTP and HTTPS connections (it will terminate the HTTPS connections) and forward all incomming connections to the backend servers in HTTP.
Meanwhile let's encrypt client will be running in the background auto renewing the certificates when they are about to expire.
Let’s Encrypt CA issues short-lived certificates (90 days). Make sure you renew the certificates at least once in 3 months.
See https://certbot.eff.org/docs/using.html#renewal for more information.
But there is a catch in our design, Let's Encrypt client using the --standalone
plugin will try to launch a webserver that will bind it self to port 80 or 443 (depending the configuration) in order to perform the domain validation.
This happens because Let's Encrypt server will try to make request to the Let's Encrypt client web server using only the port 80 or 443.
So the problem is that you can't stop HAProxy to allow that the Let's Encript client binds to the port 80 or 433 because that means downtime.
So here is a good exercise to use HAProxy proxy capabilities, our plan will to be we will have HAProxy running and binding to the 80 and 443 ports, handling incoming HTTP and HTTPS connections to our backends but when a request comes from the Let's Encrypt server trying to validate the domain, HAProxy will proxy the request to the Let's Encrypt client's web server running on a different port in this case we will be using the 63443 port.
This tutorial was created using Ubuntu 14.04 and HAProxy 1.5. The version of the letencrypt
at the time was 0.8.1.
I assume that you how a domain eg: letsencrypt.passworks.io
Update your server's package manager:
$ sudo apt-get update
Ensure th
$ sudo apt-get upgrade
Install the git and bc packages with apt-get:
$ sudo apt-get -y install git bc
We can now clone the Let’s Encrypt repository in /opt with this command:
sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt
Before installing HAProxy we need to install install
sudo apt-get install --yes software-properties-common
Install HAProxy
sudo apt-add-repository ppa:vbernat/haproxy-1.5
sudo apt-get update
sudo apt-get install --yes haproxy
frontend fe_http
log global
mode http
option httplog
bind PUBLIC_HAPROXY_IP:80
acl app_letsencrypt path_beg /.well-known/acme-challenge/
use_backend be_letsencrypt if app_letsencrypt
frontend fe_https
log global
mode http
option httplog
bind 0.0.0.0:443 ssl crt /etc/haproxy/ssl/
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
HAProxy backend rule for HTTP (80) traffic:
backend be_letsencrypt
log global
mode http
option httplog
server srv_letsencrypt 127.0.0.1:63443
Let's try to generate our certificates for passworks.io
and for the subdomain www.passworks.io
(don't forget to replace the domain passworks.io
and www.passworks.io
with or desired domain and replace [email protected]
with our own e-mail address.
To generate the certifica type:
/opt/letsencrypt/letsencrypt-auto certonly \
--authenticator standalone \
--keep-until-expiring \
--standalone-supported-challenges http-01 \
--http-01-port 63443 \
--text \
--expand \
--agree-tos \
--email [email protected] \
-d passworks.io \
-d www.passworks.io \
If everything goes right you will have your new certificates in /etc/letsencrypt/live
Now we will need to copy the new certificates to a folder where HAProxy can see them so let's start to create the folder inside the HAProxy installation folder:
mkdir -p /etc/haproxy/ssl/
Let's concat the private certificate with the full public certificate chain and make it available to HAProxy:
cat /etc/letsencrypt/live/passworks.io/{fullchain.pem,privkey.pem} > /etc/haproxy/ssl/passworks.io.pem
Now restart your hproxy and open your browser and start testing your new certificates:
sudo service haproxy reload
#!/bin/bash
# Path to the letsencrypt-auto tool
LETSENCRYPT_BIN=/opt/letsencrypt/letsencrypt-auto
# Directory where the acme client puts the generated certs
LETSENCRYPT_CERT_OUTPUT=/etc/letsencrypt/live
# Create or renew certificate for the domain(s) supplied for this tool
$LETSENCRYPT_BIN certonly \
--authenticator standalone \
--keep-until-expiring \
--standalone-supported-challenges http-01 \
--http-01-port 63443 \
--text \
--expand \
--agree-tos \
--email [email protected] \
-d passworks.io \
-d www.passworks.io \
-d brodo.passworks.io \
-d manage.passworks.io \
-d api.passworks.io
# Cat the certificate chain and the private key together for haproxy
for path in $(find $LETSENCRYPT_CERT_OUTPUT/* -type d -exec basename {} \;); do
cat $LETSENCRYPT_CERT_OUTPUT/$path/{fullchain.pem,privkey.pem} > /etc/haproxy/ssl/${path}.pem
done
Edit your crontab using sudo crontab -e
2 1,13 * * * sudo /home/ubuntu/letsencrypt/letsencrypt-passworks.sh