Install HAProxy & CertBot (LetsEncrypt)
HAProxy
Install HAProxy
Install HAProxy v2.4 with the following commands:
sudo add-apt-repository -y ppa:vbernat/haproxy-2.4
sudo apt update
sudo install -y haproxy
Install WhoIs (which includes the mkpasswd utility) with the following command:
sudo apt install whois
Generate an encrypted password for the config file for accessing the statistics with the following command:
echo <password> | mkpasswd --stdin --method=sha-256
Configure HAProxy
Edit the HAProxy configuration with this command:
sudo nano /etc/haproxy/haproxy.cfg
Inside the configuration, leave the global and defaults section as they are but add a frontend for stats and normal web access:
userlist StatsUsers
user <username> password <salted_password>
frontend http_fe
bind *:80
bind *:443 ssl crt /etc/ssl/private
# Capture additional/longer info for logs
http-request capture req.hdr(Host) len 30
capture request header User-Agent len 200
capture request header Referer len 800
capture request header X-Forwarded-For len 20
# Test URI to see if it's a LetsEncrypt request
acl letsencrypt_acl path_beg /.well-known/acme-challenge/
use_backend certbot_be if letsencrypt_acl
# The following redirect for non-https traffic breaks if used with Cloudflare Flexible Encryption
redirect scheme https code 301 if !{ ssl_fc }
# Local Stats
acl stats_acl path_beg(host) /hastats
acl stats_auth http_auth(StatsUsers)
http-request auth realm Stats if stats_acl !stats_auth
use_backend stats_be if stats_acl stats_auth
# Common Redirects
acl <redirect_acl_name> hdr_beg(host) -i <domain_prefix>
http-request redirect location <url> if <redirect_acl_name>
# <Name of website or any comment - Create these lines for every domain/backend>
acl <acl_name> hdr_beg(host) -i <domain_prefix>.
use_backend <backend_name> if <acl_name>
# Default backend if no ACL rules are matched (Can be deleted for no default)
default_backend <default_backend_name>
# <Name of the website or any comment - Create this section for every domain/backend>
backend <backend_name>
balance roundrobin
option httpchk HEAD /
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request set-header X-Forwarded-Proto https if { ssl_fc }
default-server check maxconn 20
server <server_name> <server_ip>:<server_port>
# Local stats
backend stats_be
stats enable
stats uri /hastats
stats refresh 10s
stats show-modules
no log
# Certbot for LetsEncrypt
backend certbot_be
server certbot 127.0.0.1:8888
Here's an example using an Ignition Server running on 192.168.120.10
using a domain name beginning with scada.
for remote access. This also enables HAProxy stats on any domain name using the path /hastats using a login of hastats
and a password of password
:
userlist StatsUsers
user hastats password $5$cQEGcl6Wb$nG3i246htOnuW5LTYo3O73aa7ve7i.ePiQ4v6EoMW44
frontend http_fe
bind *:80
bind *:443 ssl crt /etc/ssl/private
# Capture additional/longer info for logs
http-request capture req.hdr(Host) len 30
capture request header User-Agent len 200
capture request header Referer len 800
capture request header X-Forwarded-For len 20
# Test URI to see if it's a LetsEncrypt request
acl letsencrypt_acl path_beg /.well-known/acme-challenge/
use_backend certbot_be if letsencrypt_acl
# The following redirect for non-https traffic breaks if used with Cloudflare Flexible Encryption
redirect scheme https code 301 if !{ ssl_fc }
# Local Stats
acl stats_acl path_beg(host) /hastats
acl stats_auth http_auth(StatsUsers)
http-request auth realm Stats if stats_acl !stats_auth
use_backend stats_be if stats_acl stats_auth
# Ignition Perspective Redirect to Project URL
acl scada hdr_beg(host) -i scada.
http-request redirect location https://ignition.icstexas.com/data/perspective/client/ProjectName if scada
# Ignition
acl ignition hdr_beg(host) -i ignition.
use_backend ignition_be if ignition
# Ignition
backend ignition_be
balance roundrobin
option httpchk HEAD /
acl ignition_ping path_beg -i /main/StatusPing
http-request set-path /StatusPing if ignition_ping
option forwardfor
http-request set-header Connection "Upgrade"
http-request set-header X-Forwarded-Port %[dst_port]
http-request set-header X-Forwarded-Proto https if { ssl_fc }
default-server check maxconn 1000
server iguana 192.168.120.10:8088 check inter 10s
# Local stats
backend stats_be
stats enable
stats uri /hastats
stats refresh 10s
stats show-modules
no log
# Certbot for LetsEncrypt
backend certbot_be
server certbot 127.0.0.1:8888
Any time you modify the configuration for HAProxy, you can check the configuration for errors with the following command:
sudo haproxy -f /etc/haproxy/haproxy.cfg -c
If the configuration file is valid (warnings are OK) you can reload HAProxy with the following command:
sudo service haproxy reload
Upgrade HAProxy
If you ever need to upgrade the version to a newer version, check the following site to see if the newer version exists:
https://launchpad.net/~vbernat/+ppa-packages
If it does, use the above commands substituting in the appropriate version to add the newer version's repository and upgrade HAProxy. Once HAProxy is upgraded and verified working, use the following command to remove the old version (again substituting the old version number):
sudo add-apt-repository --remove ppa:vbernat/haproxy-2.3
Certbot (LetsEncrypt)
Install CertBot (LetsEncrypt)
Install Certbot with the following commands:
sudo add-apt-repository -y ppa:certbot/certbot
sudo apt update
sudo apt install -y certbot
Create a new certificate using HTTP authentication
We'll need to get a new certificate for the domain name we want using the following command:
sudo certbot certonly --standalone -d <domain_name> --non-interactive --agree-tos --email <admin_email> --http-01-port=8888
If this fails, you'll need to comment out the following 2 lines in your HAProxy configuration so that it only listens on port 80 and not on port 443:
# bind *:443 ssl crt /etc/ssl/private
# redirect scheme https code 301 if !{ ssl_fc }
Don't forget to reload HAProxy after making this change and once you've created the certificate, you can un-comment these lines and reload HAProxy again.
Preparing the certificate for HAProxy
To prepare the certificate in a format HAProxy can use, we'll combine the 2 files into a single certificate using the following commands:
sudo mkdir -p /etc/ssl/<domain>
sudo cat /etc/letsencrypt/live/<domain>/fullchain.pem /etc/letsencrypt/live/<domain>/privkey.pem > /etc/ssl/private/<domain>.pem
Schedule auto-renewal of certificates
We'll create a script which we'll run on a schedule to renew the certificate:
sudo nano /opt/update-certs.sh
Make the script executable:
sudo chmod +x /opt/update-certs.sh
Put the following text (update as needed) in the file:
#!/usr/bin/env bash
# Renew the certificate
certbot renew --force-renewal --tls-sni-01-port=8888
# Concatenate new cert files
bash -c "cat /etc/letsencrypt/live/<domain>/fullchain.pem /etc/letsencrypt/live/<domain>/privkey.pem > /etc/ssl/private>/<domain>.pem"
# Reload HAProxy
service haproxy reload
We'll edit the certbot cron scheduler file to schedule this script:
sudo nano /etc/cron.d/certbot
This schedule will be used to run our renewal script on the 1st day of the month every month at midnight (add it to a new line of the file):
0 0 1 * * root bash /opt/update-certs.sh