# Use set ssl cert with cert directory

**URL:** <https://discourse.haproxy.org/t/use-set-ssl-cert-with-cert-directory/5193>\
**Category:** Configuration Samples\
**Created:** [May 6, 2020, 2:17pm UTC](https://discourse.haproxy.org/t/use-set-ssl-cert-with-cert-directory/5193 "2020-05-06T14:17:45Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dbu](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.haproxy.org/dbu/32/1159_2.png) [@dbu](https://discourse.haproxy.org/u/dbu)\
**Post date:** [May 6, 2020, 2:17pm UTC](https://discourse.haproxy.org/t/use-set-ssl-cert-with-cert-directory/5193/1 "2020-05-06T14:17:45Z")

</div>

I struggled quite a bit trying to figure out how to use the new directive to dynamically update certificates with HAProxy 2.1 when loading certificates from a directory. I think i got it right now, hope it is helpful to someone (and happy for feedback). The key point i missed for quite a while was that the certificate name for “set ssl cert” is the full path to the file and not just the filename.

haproxy.cfg excerpt:

```
global
    stats socket /var/run/haproxy mode 600 level admin
frontend https-in
    bind *:443 ssl crt /etc/ssl/private/

```

script to update certificates from letsencrypt certbot:

```
#!/bin/bash

set -e

LE_DIR=/etc/letsencrypt/live
HA_DIR=/etc/ssl/private
DOMAINS=$(ls ${LE_DIR})

# update certs for HA Proxy
for DOMAIN in ${DOMAINS}
do
  # also update the file in the filesystem for when haproxy restarts
  cat ${LE_DIR}/${DOMAIN}/fullchain.pem ${LE_DIR}/${DOMAIN}/privkey.pem | tee ${HA_DIR}/${DOMAIN}.pem
  echo -e "set ssl cert /etc/ssl/private/${DOMAIN}.pem <<\n$(cat ${HA_DIR}/${DOMAIN}.pem)\n" | socat stdio /var/run/haproxy
  echo -e "commit ssl cert /etc/ssl/private/${DOMAIN}.pem" | socat stdio /var/run/haproxy
done

```

Note: This script does not work when you dynamically add new domains, as those new domains will not be known to HAProxy. From HAProxy 2.2 on, there seem to be additional commands to cover that use case, but afaik you would need to know which domain is new vs which is already existing, to run the correct thing.

---

<div class="post-metadata">

**Author:** ![bbot](https://avatars.discourse-cdn.com/v4/letter/b/b19c9b/32.png) [@bbot](https://discourse.haproxy.org/u/bbot)\
**Post date:** [March 9, 2022, 5:25pm UTC](https://discourse.haproxy.org/t/use-set-ssl-cert-with-cert-directory/5193/2 "2022-03-09T17:25:58Z")

</div>

Thanks @dbu. I’ve been using this strategy with certbot for a while now, but it stopped working recently. The issue, it turns out, is twofold.

1. The “chain.pem” file–which is included for convenience in “fullchain.pem”–issued by Let’s Encrypt now has an empty line. That blank line will need to be stripped out; otherwise, HAProxy will try to interpret part of the payload as a command and spit out “Unknown command…” errors.

2. `DOMAINS=$(ls ${LE_DIR})` doesn’t quite work anymore since `/etc/letsencrypt/live/` has a `README` file in it.

Lastly, I’d be hesitant to use `tee` since that may cause the private key to show up in logs. It may be more secure to use simple redirection (`>`).

I use the following, where “$CERT\_NAME” holds the name of the certificate (e.g. `$DOMAIN` in the original script), as issued to `certbot`'s `--cert-name` option.

```auto
LE_LIVE_DIR="/etc/letsencrypt/live/${CERT_NAME}"
LE_FULL_CERT_DIR=/etc/letsencrypt/full
FULL_CERT="${LE_FULL_CERT_DIR}/${CERT_NAME}.pem"

mkdir -p "${LE_FULL_CERT_DIR}"

# Create a single-file certificate with both the full CA chain and the
# private key. Empty lines are removed.
cat ${LE_LIVE_DIR}/fullchain.pem ${LE_LIVE_DIR}/privkey.pem | sed '/^$/d' > ${FULL_CERT}

```

Note the `sed` part, which removes the empty lines from `fullchain.pem`. Also note that I place the concatenated certificate in a new directory. Permissions and ownership should be set on the directory and file (e.g. owned by root with 600 permissions on the file).

---

<div class="post-metadata">

**Author:** ![qupfer](https://avatars.discourse-cdn.com/v4/letter/q/7ba0ec/32.png) [@qupfer](https://discourse.haproxy.org/u/qupfer)\
**Post date:** [January 9, 2023, 9:20pm UTC](https://discourse.haproxy.org/t/use-set-ssl-cert-with-cert-directory/5193/3 "2023-01-09T21:20:47Z")

</div>

I ran in the same “Unknow Command” problem.  
I helped me with a “on-the-fly” removement of empty lines via `grep .`

I use the “acme.sh” feature “reloadcmd” to run a script which cat fullchain+key to the haproxy cert folder and then I use this bash loop

```auto
for line in $(echo "show ssl cert" | socat unix-connect:/run/haproxy/admin.sock -)
do 
test -f "$line" || continue
echo -e "set ssl cert $line <<\n$(cat $line | grep . )\n" | socat unix-connect:/run/haproxy/admin.sock -
echo -e "commit ssl cert $line" | socat unix-connect:/run/haproxy/admin.sock -
done

```

Notice the piped `grep .` and remember, that I already renewed the files on the disk. So I can re-use the paths from “show ssl cert”.

And yes, in my case a simple “systemctl reload haproxy” would be easier and would not reset any connection in 99.999999% but its cool to have a cert-reload without reloading haproxy itself.

Edit: and yes, I know this discussion is a few months old, but as the commands of the official blog doesn’t work anymore ([Dynamic SSL Certificate Storage in HAProxy - HAProxy Technologies](https://www.haproxy.com/de/blog/dynamic-ssl-certificate-storage-in-haproxy/)), any additional information may help others, as its make it easier get a helpful google-hit.

---

<div class="post-metadata">

**Author:** ![matt.s](https://sea2.discourse-cdn.com/flex016/user_avatar/discourse.haproxy.org/matt.s/32/1960_2.png) [@matt.s](https://discourse.haproxy.org/u/matt.s)\
**Post date:** [May 12, 2023, 5:04am UTC](https://discourse.haproxy.org/t/use-set-ssl-cert-with-cert-directory/5193/4 "2023-05-12T05:04:46Z")

</div>

Thanks for teaching me ‘grep .’ 🙂

Also, you win a UUOC award with `cat $line | grep .`. (UUOCs are fun, I can remember the award from way, way back.). You can replace it with `grep . $line`

---

<div class="post-metadata">

**Author:** ![qupfer](https://avatars.discourse-cdn.com/v4/letter/q/7ba0ec/32.png) [@qupfer](https://discourse.haproxy.org/u/qupfer)\
**Post date:** [May 12, 2023, 5:30am UTC](https://discourse.haproxy.org/t/use-set-ssl-cert-with-cert-directory/5193/5 "2023-05-12T05:30:39Z")

</div>

Thanks for the award😅
