====== Let's Encrypt ======
* Follow [[https://www.haproxy.com/blog/haproxy-and-let-s-encrypt|Automate HAProxy Let's Encrypt certificates with acme.sh]]
* You can use my sample [[haconfig#haproxy|HAProxy Configuration]] and remove double-comments ## after replacing the [[#configure_haproxy_to_respond_to_http_challenges|account thumbprint]]
===== Install acme.sh =====
- First, on the HAProxy server, create the acme user:$ sudo adduser \
--system \
--disabled-password \
--disabled-login \
--home /var/lib/acme \
--quiet \
--force-badname \
--group \
acme
- Add the acme user to the HAProxy group:$ sudo adduser acme haproxy
- Create the directory where we will install the acme.sh program:$ sudo mkdir /usr/local/share/acme.sh/
- Then install acme.sh:$ git clone https://github.com/acmesh-official/acme.sh.git
$ cd acme.sh/
$ sudo ./acme.sh \
--install \
--no-cron \
--no-profile \
--home /usr/local/share/acme.sh
$ sudo ln -s /usr/local/share/acme.sh/acme.sh /usr/local/bin/
$ sudo chmod 755 /usr/local/share/acme.sh/
===== Generate your ACME account =====
- To generate your ACME account, switch to the acme user so the ACME account info will be stored in this user's home directory:$ sudo -u acme -s
$ acme.sh --register-account \
--server letsencrypt_test \
-m youremail@example.com
[Mon Apr 24 01:28:14 PM UTC 2023] Create account key ok.
[Mon Apr 24 01:28:14 PM UTC 2023] Registering account: https://acme-staging-v02.api.letsencrypt.org/directory
[Mon Apr 24 01:28:14 PM UTC 2023] Registered
[Mon Apr 24 01:28:14 PM UTC 2023] ACCOUNT_THUMBPRINT='lCufto4sDRTHdmWL0EugFywGV54hBCuTTXvwifi65R4'
$ exit
- Take a note of ACCOUNT_THUMBPRINT as you need this value when setting up certificate generation.
- Note that we have set the server where we'd like to register an account to be ''letsencrypt_test'', which is the Let's Encrypt staging server. It's a good idea to use this value while you test your setup. Once you've verified that everything is working, register again using a server value of ''letsencrypt''.
===== Configure HAProxy to Respond to HTTP Challenges =====
- Start by creating the directory for certificates:$ sudo mkdir /etc/haproxy/certs
$ sudo chown haproxy:haproxy /etc/haproxy/certs
$ sudo chmod 770 /etc/haproxy/certs
- Edit ''/etc/haproxy/haproxy.cfg'' to add the challenge response and the thumbprint:global
stats socket /var/run/haproxy/admin.sock level admin mode 660
setenv ACCOUNT_THUMBPRINT 'lCufto4sDRTHdmWL0EugFywGV54hBCuTTXvwifi65R4'
frontend web
bind :80
bind :443 ssl crt /etc/haproxy/certs/ strict-sni
http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].${ACCOUNT_THUMBPRINT}\n" if { path_beg '/.well-known/acme-challenge/' }
- Restart the HAProxy service:$ sudo systemctl restart haproxy
===== Generate and deploy certificate =====
- Generate a certificate (once tested use ''letsencrypt'' instead of ''letsencrypt_test''):$ sudo -u acme -s
$ acme.sh --issue \
-d example.com \
--stateless \
--server letsencrypt_test
[Mon Apr 24 01:36:03 PM UTC 2023] Using CA: https://acme-staging-v02.api.letsencrypt.org/directory
[Mon Apr 24 01:36:03 PM UTC 2023] Single domain=example.com'
[Mon Apr 24 01:36:03 PM UTC 2023] Getting domain auth token for each domain
[Mon Apr 24 01:36:04 PM UTC 2023] Getting webroot for domain='example.com'
[Mon Apr 24 01:36:04 PM UTC 2023] Verifying: example.com
[Mon Apr 24 01:36:04 PM UTC 2023] Stateless mode for domain:example.com
[Mon Apr 24 01:36:06 PM UTC 2023] Success
[Mon Apr 24 01:36:06 PM UTC 2023] Verify finished, start to sign.
[Mon Apr 24 01:36:06 PM UTC 2023] Lets finalize the order.
[Mon Apr 24 01:36:06 PM UTC 2023] Le_OrderFinalize='https://acme-staging-v02.api.letsencrypt.org/acme/finalize/12345'
[Mon Apr 24 01:36:06 PM UTC 2023] Downloading cert.
[Mon Apr 24 01:36:06 PM UTC 2023] Le_LinkCert='https://acme-staging-v02.api.letsencrypt.org/acme/cert/abc12345'
[Mon Apr 24 01:36:06 PM UTC 2023] Cert success.
-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----
[Mon Apr 24 01:36:06 PM UTC 2023] Your cert is in: /var/lib/acme/.acme.sh/example.com_ecc/example.cer
[Mon Apr 24 01:36:06 PM UTC 2023] Your cert key is in: /var/lib/acme/.acme.sh/example.com_ecc/example.key
[Mon Apr 24 01:36:06 PM UTC 2023] The intermediate CA cert is in: /var/lib/acme/.acme.sh/example.com_ecc/ca.cer
[Mon Apr 24 01:36:06 PM UTC 2023] And the full chain certs is there: /var/lib/acme/.acme.sh/example.com_ecc/fullchain.cer
- I have written a small bash file so I don't need to enter the command parameters every timesudo vim /var/lib/acme/batch/generate.sh
#!/bin/bash
#
# generate certificate for $1 domain and $2...$n alternative domains
if [ $# -eq 0 ]; then
echo "usage: $0 ..."
else
COMMAND=(acme.sh "--issue")
for arg in "$@"; do
COMMAND+=("-d" ${arg})
done
COMMAND+=("--stateless" "--server letsencrypt")
"${COMMAND[@]}"
fi
:wq
sudo chown acme:acme /var/lib/acme/batch/generate.sh
ln -s /var/lib/acme/batch/generate.sh /usr/local/bin/generate.sh
- Once the certificate is generated, you can deploy it to the /etc/haproxy/certs directory and enable it in HAProxy without needing to reload:$ sudo -u acme -s
$ DEPLOY_HAPROXY_HOT_UPDATE=yes \
DEPLOY_HAPROXY_STATS_SOCKET=/run/haproxy/admin.sock \
DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy/certs \
acme.sh --deploy -d example.com --deploy-hook haproxy
[Mon Apr 24 02:17:31 PM UTC 2023] The domain 'example.com' seems to have a ECC cert already, lets use ecc cert.
[Mon Apr 24 02:17:31 PM UTC 2023] Deploying PEM file
[Mon Apr 24 02:17:31 PM UTC 2023] Moving new certificate into place
[Mon Apr 24 02:17:31 PM UTC 2023] Creating new certificate '/etc/haproxy/certs/example.com.pem' over HAProxy stats socket.
[Mon Apr 24 02:17:31 PM UTC 2023] Success
- I have written a small bash file so I don't need to enter the command parameters every timesudo vim /var/lib/acme/batch/deploy.sh
#!/bin/bash
#
# deploy certificate for $1 domain
if [ $# -eq 0 ]; then
echo "usage: deploy.sh "
else
DEPLOY_HAPROXY_HOT_UPDATE=yes \
DEPLOY_HAPROXY_STATS_SOCKET=/run/haproxy/admin.sock \
DEPLOY_HAPROXY_PEM_PATH=/etc/haproxy/certs \
acme.sh --deploy -d $1 --deploy-hook haproxy
fi
:wq
sudo chown acme:acme /var/lib/acme/batch/deploy.sh
ln -s /var/lib/acme/batch/deploy.sh /usr/local/bin/deploy.sh
- Check if the certificate was added in HAProxy with socat:$ echo "show ssl cert /etc/haproxy/certs/example.com.pem" |\
socat /var/run/haproxy/admin.sock -
Filename: /etc/haproxy/certs/example.com.pem
Status: Used
Serial: 6C058BA29A03DF58BFA9CF0ABD0C0AB8
notBefore: Apr 24 13:35:04 2023 GMT
notAfter: Apr 25 13:36:04 2023 GMT
Subject Alternative Name: DNS:example.com
Algorithm: EC256
SHA1 FingerPrint: 7A6A64B2D3BB1E548DBF383FDB3A7CA8434B3F5A
[...]
- If the dry run works go back to [[#generate_your_acme_account|account registration]] and do everything with ''letsencrypt'' production server.
===== Certificate renewal =====
- Install a crontab directive for the acme user:$ sudo -u acme -s
$ crontab -e
$ acme.sh --install-cronjob
===== Check certificates =====
* List All Certificates:acme.sh --list
* View Details for a Specific Domain:acme.sh --info -d domain.com
* Check Live Certificate Expiration (OpenSSL):openssl x509 -in ~/.acme.sh/domain.com_ecc/domain.com.cer -noout -text | grep -A 2 "Validity"
==== Links ====
* [[https://www.keytos.io/blog/pki/what-is-acme-protocol/|ACME Protocol Explained]]
* [[https://www.haproxy.com/blog/haproxy-and-let-s-encrypt|Automate HAProxy Let's Encrypt certificates with acme.sh]]