Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
FREEDOM251

Freedom251 › Blog › ACME

How to Secure HAProxy With Let’s Encrypt

By Freedom251 Team · · 15 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

HAProxy can terminate HTTPS and obtain Let’s Encrypt certificates in three practical ways: native ACME support in newer HAProxy releases, an external client such as acme.sh, or Certbot. The reliable design is the same in every case: make the ACME challenge reachable, store a PEM bundle containing the certificate and private key, load that bundle into HAProxy, and automate renewal with a deployment step that you can monitor.

Use native ACME when your installed version supports it and you want issuance centralized in HAProxy. Use acme.sh when you need stateless HTTP-01 handling and Runtime API activation without restarting the process. Use Certbot when your operating system already standardizes it or when you need standalone or webroot issuance. Test against the Let’s Encrypt staging directory before requesting production certificates.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What HAProxy needs from Let’s Encrypt

Let’s Encrypt validates control of a hostname before issuing a certificate. HAProxy is usually the public endpoint, so it must either answer the validation request itself or route it to a component that can. After issuance, HAProxy presents the certificate on its TLS listener and uses the private key to complete the handshake.

HAProxy expects a certificate file that contains the private key and the certificate chain in one PEM bundle. A common bundle order is the private key followed by the full certificate chain, although the exact order and file layout should match the HAProxy package and configuration on your system. The service account running HAProxy must be able to read the file, while ordinary users must not be able to read the private key.

  • HTTP-01: Let’s Encrypt connects to http://your-host/.well-known/acme-challenge/<token> on public port 80. The request must reach the HAProxy frontend that serves the challenge.
  • DNS-01: The ACME client creates a TXT record under _acme-challenge.your-host through your DNS provider’s API. This works even when port 80 is unavailable and can issue wildcard certificates.
  • Certificate activation: HAProxy can load a renewed PEM through its certificate store or Runtime API. A Runtime API deployment can activate the new certificate without restarting the HAProxy process when the integration supports it.

Choose an issuance method

Method Version or requirement Challenge handling Renewal activation Operational trade-off
Native HAProxy ACME HTTP-01 is documented for HAProxy 3.2 and newer; DNS-01 is documented for 3.3 and newer HAProxy’s ACME section handles the challenge; DNS-01 also needs a supported provider and API credentials ACME task and certificate-store/Runtime API workflow; HAProxy 3.2 needs an initial dummy certificate Most centralized design, but tied to the capabilities and configuration syntax of the installed release
acme.sh with HAProxy Runtime API HAProxy 2.2 and newer can use the improved certificate-loading behavior described by HAProxy Technologies HAProxy returns the HTTP-01 response in stateless mode, or acme.sh can use a DNS provider Deployment hooks update the certificate through the Runtime API without a process restart Flexible across older HAProxy versions, but requires socket permissions, hooks and monitoring
Certbot Works across more HAProxy versions because issuance is external; HAProxy installation support is best effort --standalone temporarily owns port 80; --webroot writes challenge files that an HTTP server must expose Run scheduled certbot renew and deploy or reload the HAProxy certificate according to your integration Familiar on many Linux systems, but certificate installation and reload behavior need local validation

For a single load balancer running a documented HAProxy 3.2 or newer release, native ACME is the shortest control path. For an older installation, or when you already operate acme.sh, the Runtime API pattern avoids replacing the HAProxy process. Certbot is useful when a distribution already manages it, but do not assume that successful issuance automatically updates HAProxy.

Prepare HAProxy before requesting a certificate

Confirm DNS and network reachability

  1. Create the required A and, if used, AAAA records for each hostname. They must resolve to the public address that actually reaches HAProxy.
  2. For HTTP-01, allow inbound TCP port 80 through every firewall, security group, NAT rule and upstream load balancer. Let’s Encrypt must be able to reach the same frontend from the public Internet.
  3. Allow TCP port 443 for normal HTTPS traffic. If another service already binds either port, decide whether it will proxy the challenge or whether HAProxy will own the listener.
  4. For DNS-01, create an API credential limited to the required DNS zone and record operations. Do not give an ACME process broad account permissions when a zone-scoped token is available.

Create protected certificate locations

Use a directory dedicated to HAProxy certificates, such as /etc/haproxy/certs, with ownership and mode that prevent unprivileged reads. The exact service user varies by distribution. A typical policy is a root-owned directory, a group-readable certificate file for the HAProxy service group, and mode 0640 or stricter. The private key must never be placed in a world-readable webroot or committed to configuration management logs.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Enable a controlled Runtime API socket

If you plan to deploy certificates without restarting, configure a local HAProxy stats socket with an explicit filesystem path and restrictive permissions. Limit access to the account that performs certificate deployment. A socket exposed over an unrestricted network address can allow administrative operations and should not be used merely for convenience.

Keep a rollback copy

Before the first automated deployment, save the currently working PEM and HAProxy configuration. A failed renewal should not remove the last valid certificate. Keep enough historical copies to restore the previous certificate and use HAProxy’s configuration check before any file-based reload.

Path A: native HAProxy ACME

The official HAProxy tutorial documents native ACME for HAProxy 3.2 and newer. HTTP-01 is available in the 3.2 documentation; DNS-01 is documented for 3.3 and newer. Check the exact syntax and feature set of the binary installed on your host rather than copying a configuration intended for another minor release.

1. Build the native ACME configuration

Add the global directives required by your HAProxy release, define an acme section that points to the Let’s Encrypt staging directory, and define a crt-store for the generated PEM. The store path must be writable by the process or by the controlled deployment mechanism, but not by ordinary users.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Your frontend needs both listeners. Bind port 80 for HTTP-01 and port 443 for TLS. Requests under /.well-known/acme-challenge/ must be returned by the ACME handler. Other port-80 requests can be redirected to HTTPS. The TLS bind selects the certificate generated in the certificate store; if SNI serves several names, make sure the store and bind rules cover every name.

2. Start HAProxy with a bootstrap certificate

On HAProxy 3.2, create a dummy certificate so the process can start before the first certificate has been issued. The dummy certificate is only a bootstrap artifact; it must not be mistaken for a production certificate. Once the ACME flow has completed, persist the real certificate in the configured store.

3. Request through the Runtime API

Use the Runtime API command acme renew to initiate or renew the configured certificate. Inspect the ACME task status after the command returns; a successful command submission does not by itself prove that validation and issuance succeeded.

After issuance, use dump ssl cert through the Runtime API to persist the resulting certificate to the configured certificate-store path. Confirm that the dumped PEM contains the private key and complete chain expected by HAProxy, then verify the certificate’s subject, alternate names and expiration date.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

4. Move from staging to production

Keep the staging directory while testing routing, permissions and certificate loading. Staging certificates are not trusted by browsers and are intended to prevent production rate-limit problems. After a complete staging issuance and activation test, change the ACME directory to Let’s Encrypt production and run the issuance workflow again.

5. Configure DNS-01 when HTTP-01 is unsuitable

Native DNS-01 requires HAProxy 3.3 or newer in the documented workflow. Configure one supported DNS provider and supply credentials through the mechanism required by that provider integration. HAProxy’s documented provider list includes Azure, Cloudflare, DigitalOcean, Google Cloud DNS, GoDaddy, Hetzner, IONOS, Linode, Namecheap, OVH, Porkbun, Route 53, Scaleway and Vultr.

DNS-01 is preferable when port 80 cannot be exposed, when the service is internal, or when you need a wildcard certificate. It introduces DNS propagation and API-permission failure modes, so monitor the TXT record creation and cleanup as carefully as the certificate task itself.

Path B: acme.sh with HAProxy’s Runtime API

acme.sh issues and renews Let’s Encrypt certificates, while HAProxy answers the HTTP challenge and loads the renewed PEM. HAProxy Technologies describes this as a stateless arrangement: “When configuring HAProxy, it’s important to understand that acme.sh operates in a stateless mode as an ACME client, meaning it does not generate response to Let’s Encrypt challenges dynamically, but rather relies on HAProxy to handle the HTTP challenge.”

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

1. Route the HTTP-01 token in HAProxy

The frontend must return the token body exactly as Let’s Encrypt expects. A representative rule from the HAProxy guide is:

http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].${ACCOUNT_THUMBPRINT}n" if { path_beg '/.well-known/acme-challenge/' }

Place the rule on the public port-80 frontend, before a blanket redirect to HTTPS. The condition must match only the ACME path; ordinary HTTP requests can still redirect. If another proxy sits in front of HAProxy, preserve the path and do not cache or rewrite the challenge response.

2. Configure the socket and certificate deployment

Give acme.sh access to the local Runtime API socket without giving it unrestricted shell access to the HAProxy host. The deployment hook should upload the new PEM, commit it through the Runtime API, and activate it for the relevant certificate store. The HAProxy guide states that HAProxy 2.2 and newer can use improved certificate loading so renewed certificates can be activated without restarting the process.

Use a dedicated deploy account, store the account key and provider credentials with restrictive permissions, and log the result of every deployment. A renewal job that obtains a certificate but fails to activate it is an outage waiting to happen.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Test with staging, then issue in production

Point acme.sh at the Let’s Encrypt staging server first. Request a certificate, verify that the token reaches HAProxy, confirm the PEM is written to the intended location, and check the certificate through an external TLS client. Only then switch the account and directory settings to production.

4. Verify a no-restart renewal

Perform a controlled renewal while watching the HAProxy Runtime API and service logs. Existing TLS connections should continue while the new certificate becomes available for subsequent handshakes. Test a new connection with SNI after deployment, and retain the previous PEM until the new certificate has passed validation.

Path C: Certbot with HAProxy

Certbot’s HAProxy instructions offer two issuance modes. Choose standalone when Certbot can temporarily take port 80. Choose webroot when an existing web server remains active and can serve files from the ACME challenge directory.

Standalone mode

Stop or otherwise free the port-80 listener, then run a command such as:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

sudo certbot certonly --standalone -d example.com -d www.example.com

Replace the example names with the names on your certificate. Standalone mode fails if HAProxy or another process still owns port 80, and stopping a production listener creates a validation window. Schedule standalone renewals only when the resulting interruption is acceptable and the stop/start sequence is tested.

Webroot mode

Create a directory that the public HTTP frontend can serve, then request the certificate with a command such as:

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

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

HAProxy routing must preserve /.well-known/acme-challenge/ and send it to the webroot-serving backend. Test an ordinary file at that exact path from outside your network before requesting a certificate. A redirect that changes the path, an authentication rule, or a backend that is reachable only internally will cause validation to fail.

Install the resulting PEM

Certbot normally stores the certificate, chain and private key as separate files. HAProxy generally needs a combined PEM. For a certificate named example.com, an illustrative assembly command is:

sudo sh -c 'cat /etc/letsencrypt/live/example.com/fullchain.pem /etc/letsencrypt/live/example.com/privkey.pem > /etc/haproxy/certs/example.com.pem'

Use the order and file names required by your HAProxy package, then apply the correct owner and mode. Validate the HAProxy configuration before reloading. If your deployment uses the Runtime API, upload and commit the PEM there instead of relying on a process restart.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Schedule renewal and deployment

Certbot documents recurring certbot renew execution, commonly twice daily with a randomized delay. The renewal command normally does nothing until a certificate is near expiry, so frequent scheduling is safe. Add a deploy hook that assembles the HAProxy PEM and reloads or updates the certificate only after Certbot reports a successful renewal. Certbot labels HAProxy installation support as best effort; validate the hook, package paths and reload command on your distribution.

HTTP-01 or DNS-01?

Decision factor HTTP-01 DNS-01
Network requirement Public TCP port 80 must reach the HAProxy challenge frontend No inbound HTTP challenge is required; the ACME client needs DNS API access
Wildcard certificates Not supported Supported through a TXT record under _acme-challenge
Typical failure Wrong DNS address, blocked port 80, redirect or path rewrite Invalid API token, wrong zone, delayed propagation or stale TXT data
Operational exposure Simple routing rule and no DNS secret on HAProxy Requires a narrowly scoped DNS credential and careful secret storage
Best fit Public websites with stable port-80 routing Private services, wildcard names, or environments where port 80 cannot be opened

Do not choose DNS-01 merely because it sounds more secure. It moves the trust boundary to the DNS provider: compromise of the credential can alter records in the zone. Conversely, do not force HTTP-01 onto a topology where a CDN, firewall or second load balancer cannot guarantee that the token reaches HAProxy.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Load and activate certificates safely

File-based reload

A file-based deployment writes the new PEM, validates the HAProxy configuration, and performs the distribution’s normal graceful reload. This is straightforward and works with clients that do not integrate with the Runtime API, but the reload command, service account and certificate path must be tested. A failed reload can leave the old process serving traffic or prevent the new process from starting.

Runtime API activation

Runtime deployment avoids replacing the HAProxy process when the certificate-loading workflow supports it. The usual sequence is to identify the certificate-store path, upload the PEM through the protected stats socket, commit the change, and verify the active certificate. Native ACME uses commands such as acme renew and dump ssl cert; external clients use their deployment hooks to perform the equivalent update.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

After activation, test a new TLS connection with the correct SNI and inspect the served chain. Existing long-lived connections may continue using the certificate negotiated when they were established; the important check is that new handshakes receive the renewed certificate.

Automate renewal and make failures visible

A certificate is not secured once; it must be renewed before expiration and activated consistently. Use one scheduler, not several overlapping jobs, and record the certificate name, renewal result, deployment result and expiration date.

  • Native HAProxy: monitor the ACME task status and alert when a renewal task fails or remains pending.
  • acme.sh: capture the client and deployment-hook exit status, then verify the Runtime API commit and the certificate presented on port 443.
  • Certbot: run scheduled certbot renew with a deploy hook and alert on non-zero exit status, hook failure or an unchanged certificate near its expiry date.

Renewal monitoring should check the externally served certificate, not just the file timestamp. A new file may exist while HAProxy still serves the old certificate because a reload, commit or SNI mapping failed.

Active-active HAProxy and multiple nodes

The native tutorial targets a single load balancer. In an active-active pair, each node must either complete ACME independently or receive a securely distributed certificate. Independent HTTP-01 validation requires both public paths to return the same token, which is difficult when traffic is split unpredictably. DNS-01 can simplify validation, but the resulting PEM still has to reach every node.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose one deployment authority, distribute the certificate over an authenticated channel, set restrictive permissions on each destination, and activate it locally. Never copy private keys through an unencrypted administrative channel or place them in a shared filesystem without access controls. Test failover after renewal so that the standby node is not left with an expired certificate.

Troubleshooting checklist

Validation never reaches HAProxy

  • Resolve the hostname’s A and AAAA records from an external network and compare them with the public HAProxy address.
  • Confirm that TCP port 80 reaches the intended frontend, not an old server, maintenance page or upstream proxy.
  • Request the exact path /.well-known/acme-challenge/test and inspect the status, body and redirects. HTTP-01 requires the token path to remain intact.
  • Check firewall, NAT, security-group and load-balancer rules in that order. A local curl test cannot prove public reachability if the request never leaves your network.

The token response is wrong

  • Ensure the HAProxy return rule appears before a catch-all redirect or authentication rule.
  • For acme.sh stateless mode, preserve the token and account thumbprint exactly; do not add HTML, compression text or a trailing rewrite.
  • Verify that a second frontend, CDN or WAF is not caching a previous token.

DNS-01 cannot create or see the TXT record

  • Check that the API credential can edit the authoritative zone for the requested name.
  • Confirm that the client is updating the correct zone when the hostname is several labels deep.
  • Query authoritative DNS servers directly and allow for propagation before declaring the challenge failed.
  • Remove stale TXT values only when the ACME client instructs you to; concurrent renewals can require more than one valid value.

HAProxy will not start with the certificate

  • Inspect the PEM and verify that it contains a private key and a complete chain in the format your HAProxy build accepts.
  • Check owner, group and mode on every parent directory, not only the PEM file. The HAProxy service account needs execute permission on directories and read permission on the file.
  • Look for a mismatch between the configured certificate-store path and the path used by Certbot, acme.sh or the native ACME section.
  • Run the distribution’s HAProxy configuration check before reloading. Restore the previous known-good PEM if validation fails.

The Runtime API update fails

  • Verify that the deployment account can open the stats socket and that the socket path has not changed after a package upgrade.
  • Check whether the certificate was uploaded but not committed. Runtime API workflows commonly require a distinct commit step.
  • Inspect HAProxy logs and the ACME client’s deployment log for permission, parsing and certificate-store errors.
  • Confirm the active certificate with a new SNI-aware TLS connection rather than relying on the file modification time.

Renewal succeeds but clients still see the old certificate

Separate issuance from activation. Confirm the new certificate’s expiration date in the PEM, then confirm that HAProxy loaded the same path or Runtime API object. Check every SNI certificate selection rule and every node behind the public address. In a cluster, one node may have renewed while another still serves the old certificate.

Security and operational hardening

  • Start with Let’s Encrypt staging to avoid consuming production issuance limits during configuration work.
  • Use DNS credentials restricted to the required zone and protect them like private keys.
  • Keep the Runtime API socket local and permissioned; do not expose administrative commands on an unauthenticated network listener.
  • Separate certificate issuance privileges from general shell administration where practical.
  • Retain the last valid PEM until the replacement has been served successfully.
  • Alert before expiration and on every failed renewal or deployment, rather than relying on a monthly manual check.
  • Document which component owns port 80, which path serves HTTP-01, where PEM files are assembled, and how to roll back.
  • Test renewal in the same topology used in production, including redirects, IPv6, SNI, firewalls and failover nodes.

A practical decision sequence

  1. Check the installed HAProxy version. If it is 3.2 or newer, evaluate native HTTP-01; if it is 3.3 or newer and DNS automation is needed, evaluate native DNS-01.
  2. If native ACME is unavailable or you prefer external lifecycle management, choose acme.sh for Runtime API activation or Certbot for standalone/webroot workflows.
  3. Choose HTTP-01 only when public port 80 and the challenge path can be routed reliably. Choose DNS-01 for wildcard names, private services or restricted HTTP ingress.
  4. Build the PEM and permission model before requesting production certificates.
  5. Run a complete staging issuance, activation, external TLS check and rollback test.
  6. Switch to production, schedule renewal, and alert on both issuance and activation failures.

Following this sequence keeps certificate issuance, HAProxy configuration and renewal operations separate enough to troubleshoot while still automating the full lifecycle.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

ACMEacme.shCertbotDNS-01HAProxyHTTP-01HTTPSLet’s EncryptRuntime APITLS

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.