Skip to content
ssldays

Guide

Where haproxy stores SSL certificates and renewal

Map haproxy ssl certificate path layout: bind crt directories, crt-list files, Certbot deploy hooks, permissions, and reload order for clean renewals.

Updated May 30, 2026 815 words

Knowing haproxy ssl certificate path conventions prevents the classic renewal gap: Certbot writes under /etc/letsencrypt/live, while HAProxy still reads a concat PEM under /etc/haproxy/certs nobody updated in the deploy hook.

Operations teams standardize on directory binds, symlink farms, or explicit crt-list CSV files. Each pattern changes where you drop renewed material and whether a simple Certbot --deploy-hook is enough.

This guide maps haproxy ssl certificate path choices to renewal workflows—ACME versus manual OV—so the serial on disk, in config, and on the wire stay aligned after every rotation.

Infrastructure-as-code repos should version crt-list beside haproxy.cfg with the same pull request discipline as firewall rules. Drift between Terraform-rendered lists and manually dropped PEM files is the dominant cause of haproxy ssl certificate path confusion during auditor requests for evidence.

Quarterly access reviews on deployment keys used by hooks prevent orphaned service accounts from writing to cert directories with wrong ownership after personnel changes.

What to check

Read the active config HAProxy runs, not only templates in Git. haproxy -vv and ps output show which -f file path the daemon uses.

Document whether each frontend references a single file, a directory, or crt-list. Renewals must touch every path the running config names.

Note Linux permissions: the haproxy user must read private keys after renew without making keys world-readable.

When multiple environments share a repo, confirm production symlinks point at the intended live directory, not staging paths checked into examples.

Container images that embed HAProxy should document whether PEM paths live on ephemeral layers or mounted volumes. Kubernetes Secrets mounted as directories pair well with bind crt folder patterns when file names match hostname conventions.

Step-by-step

Discover running certificate paths

sudo haproxy -c -f /etc/haproxy/haproxy.cfg 2>&1 | head
grep -Rn 'crt \|crt-list' /etc/haproxy/

Example directory bind:

frontend https_front
  bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1

Example crt-list bind:

bind *:443 ssl crt-list /etc/haproxy/certs.txt

Inspect crt-list mappings

cat /etc/haproxy/certs.txt

Typical lines map hostnames or sni patterns to PEM paths. Update the path column when you version filenames.

List current PEM inventory

sudo ls -la /etc/haproxy/certs/
for f in /etc/haproxy/certs/*.pem; do
  echo "== $f"
  openssl x509 -in "$f" -noout -subject -dates -serial 2>/dev/null || true
done

Standardize Certbot deploy to HAProxy paths

sudo certbot certonly --webroot -w /var/www/html -d example.com

Create /etc/letsencrypt/renewal-hooks/deploy/haproxy.sh:

#!/bin/bash
set -euo pipefail
DOMAIN="${RENEWED_LINEAGE##*/}"
DEST="/etc/haproxy/certs/${DOMAIN}.pem"
cat "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" \
    "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" > "${DEST}"
chmod 640 "${DEST}"
chown root:haproxy "${DEST}"
systemctl reload haproxy
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/haproxy.sh

Manual commercial renewal path

Export PFX or PEM from your CA, convert if needed, write to the path crt-list references, preserve backups:

sudo install -m 640 -o root -g haproxy new-example.pem /etc/haproxy/certs/example.pem
sudo haproxy -c -f /etc/haproxy/haproxy.cfg && sudo systemctl reload haproxy

Verify live serial

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -serial -dates

Inventory and rotation calendar

Maintain a living spreadsheet exported from crt-list with notAfter, hook name, and owner team. Free tools beat heroic memory when seventy hostnames share one HAProxy pair. Tie inventory updates to CMDB hostname creation so new brands do not launch without deploy hooks wired to the agreed haproxy ssl certificate path standard.

Run quarterly fire drills: stage a fake renew on a canary hostname, execute deploy hook, reload, and compare serial externally. Record elapsed minutes to set executive expectations for real renewals.

How to read the output

ls -la reveals whether operators use symlinks from /etc/haproxy/certs/example.pem to live/example trees—symlinks simplify renew but break when Certbot live directory rotates and symlinks are not updated.

crt-list first column patterns follow HAProxy SNI rules; a typo sends traffic to the default cert with unexpected notAfter.

openssl x509 on each PEM before reload shows which file is mid-expiry. Compare list against inventory spreadsheets.

Certbot deploy hook logs in /var/log/letsencrypt/letsencrypt.log confirm hooks ran—absence means renewal succeeded but HAProxy paths never changed.

Common mistakes

Pointing crt at fullchain.pem without appending privkey.pem in a single bundle HAProxy expects for file loads.

Maintaining duplicate PEM copies in certs/ and ssl/ trees, renewing only one.

Forgetting crt-list entries when adding a new marketing domain—default cert expires first on that hostname.

Running hooks as root that chown keys to root:root, denying HAProxy read until the next incident.

Using world-readable 644 keys to “fix” permissions—use group haproxy instead.

Skipping test reload after path edits, discovering syntax errors during the production change window.

Blue-green HAProxy farms need hooks on both colors or shared NFS cert trees with identical paths; asymmetric layouts mean Color B serves expired paths while Color A was fixed during a rushed incident.

Document emergency rollback: retain the previous PEM generation in a versioned backup folder so operators can restore crt-list pointers quickly if a new bundle mis-orders chain and key during a late-night deploy hook.

When auditors ask for evidence of haproxy ssl certificate path governance, export redacted haproxy -c output, hook source, and external openssl in one PDF per hostname. That bundle closes compliance questions faster than screenshots of file explorers alone.

Train new operators with a lab pair where they must trace a hostname from crt-list through hook logs to openssl without escalations—skills transfer better than wiki reading alone.

When to use automation

Path discipline erodes when multiple engineers deploy hooks differently per datacenter. External TLS monitoring catches the one node whose hook failed silently.

ssldays validates live TLS presentation independent of filesystem layout—ideal after you standardize haproxy ssl certificate path conventions. RDAP tracks registration where available. Threshold emails at 30, 14, 7, and 1 days complement Certbot timers. Paid Starter and Pro add Slack and Discord webhooks. Free tier monitors three domains daily; Starter 25 hourly; Pro 100 hourly.

After hook changes, spot-check on live check and register hostnames at register. Coordinate multi-path fleets with acme.sh renewal monitoring when not using Certbot.

Frequently asked questions

One directory bind or crt-list?

Directories suit fewer certs; crt-list scales SNI-rich estates. Pick one pattern per fleet for operational clarity.

Do I need to restart HAProxy?

reload suffices when paths stay constant. Changing crt-list location requires config test then reload.

How are wildcard certs named?

Use a clear filename convention in crt-list or certs/ and document SAN coverage in your cert inventory.

What about HAProxy Enterprise?

Vendor builds follow the same bind crt semantics—validate against the running config snapshot either way.

Monitor this hostname on a schedule

Live certificate checks and renewal reminders — not guesswork from PEM files.