SSL/TLS

Enable TLS by using the ACME protocol

This page applies to:

  • HAProxy 3.2 and newer
  • HAProxy Enterprise 3.2r1 and newer

Experimental feature

Enabling the ACME protocol to manage TLS certificates is currently experimental.

With the ACME (Automatic Certificate Management Environment) protocol, you can integrate with certificate issuers to automate the process of obtaining and renewing TLS certificates. The ACME protocol is an open standard that’s widely supported by both free and paid certificate issuers. By enabling ACME at the proxy layer, you can:

  • Offload the integration details and avoid a custom implementation in your applications.
  • Ensure a single tier for managing the certificate issuer’s validation of your domain and the process of certificate renewals.
  • Maintain a consistent approach for certificate management across heterogeneous applications.

This feature works with a single load balancer, but not an active-active pair, due to the need to communicate with the certificate issuer’s servers.

Let’s Encrypt Jump to heading

In this section, learn how to configure the load balancer to use the ACME provider named Let’s Encrypt to get a TLS certificate.

HTTP-01 challenge Jump to heading

This section applies to:

  • HAProxy 3.2 and newer
  • HAProxy Enterprise 3.2r1 and newer

We’ll use an HTTP-01 challenge type. The challenge allows the Let’s Encrypt servers to verify that you control the domain for which you’re requesting a certificate. In this case, HAProxy hosts a file at a well-known URL path, which Let’s Encrypt verifies.

To get a certificate from Let’s Encrypt:

  1. HAProxy 3.2 / HAProxy Enterprise 3.2: In version 3.2, you must generate a dummy TLS certificate. This certificate serves as a placeholder, allowing HAProxy to start and preventing an error that would happen if it tried to read a certificate that doesn’t yet exist on the filesystem. You don’t need to do this in later versions.

    • Generate a dummy TLS certificate file, which we’ll later overwrite with the Let’s Encrypt certificate. The load balancer needs a file on the filesystem at startup.

      nix
      cd ~
      openssl req -x509 \
      -newkey rsa:2048 \
      -keyout example.key \
      -out example.crt \
      -days 365 \
      -nodes \
      -subj "/C=US/ST=Ohio/L=Columbus/O=MyCompany/CN=www.example.com"
      cat example.key example.crt > example.pem
      nix
      cd ~
      openssl req -x509 \
      -newkey rsa:2048 \
      -keyout example.key \
      -out example.crt \
      -days 365 \
      -nodes \
      -subj "/C=US/ST=Ohio/L=Columbus/O=MyCompany/CN=www.example.com"
      cat example.key example.crt > example.pem
    • Copy the PEM file to the directory. For example:

      nix
      sudo mkdir /etc/haproxy/ssl
      sudo cp example.pem /etc/haproxy/ssl
      nix
      sudo mkdir /etc/haproxy/ssl
      sudo cp example.pem /etc/haproxy/ssl
  2. HAProxy 3.3 / HAProxy Enterprise 3.3 and newer: Starting in version 3.3, HAProxy generates event notifications when it creates or updates a certificate from an ACME provider, and the HAProxy Data Plane API watches for these events. Together, they automate saving the certificates to the filesystem. Previously, you had to call the Runtime API function dump ssl cert to save the certificate from HAProxy’s runtime memory to a file.

    • Install the HAProxy Data Plane API.

    • Find the path to the HAProxy master socket, by calling systemctl status to get the value of the -S parameter.

      nix
      sudo systemctl status haproxy
      nix
      sudo systemctl status haproxy
      output
      text
      ● haproxy.service - HAProxy Load Balancer
      Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; preset: enabled)
      Active: active (running) since Mon 2026-04-06 14:39:32 UTC; 33min ago
      Docs: man:haproxy(1)
      file:/usr/share/doc/haproxy/configuration.txt.gz
      Main PID: 2366 (haproxy)
      Status: "Ready."
      Tasks: 3 (limit: 9433)
      Memory: 69.2M (peak: 70.8M)
      CPU: 63ms
      CGroup: /system.slice/haproxy.service
      ├─2366 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
      └─2368 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
      output
      text
      ● haproxy.service - HAProxy Load Balancer
      Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; preset: enabled)
      Active: active (running) since Mon 2026-04-06 14:39:32 UTC; 33min ago
      Docs: man:haproxy(1)
      file:/usr/share/doc/haproxy/configuration.txt.gz
      Main PID: 2366 (haproxy)
      Status: "Ready."
      Tasks: 3 (limit: 9433)
      Memory: 69.2M (peak: 70.8M)
      CPU: 63ms
      CGroup: /system.slice/haproxy.service
      ├─2366 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
      └─2368 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
      nix
      sudo systemctl status hapee-3.3-lb
      nix
      sudo systemctl status hapee-3.3-lb
      output
      text
      ● hapee-3.3-lb.service - HAPEE Load Balancer
      Loaded: loaded (/usr/lib/systemd/system/hapee-3.3-lb.service; enabled; preset: enabled)
      Active: active (running) since Tue 2026-05-12 14:30:38 UTC; 39min ago
      Main PID: 556 (hapee-lb)
      Status: "Ready."
      Tasks: 3 (limit: 4520)
      Memory: 26.1M (peak: 26.5M)
      CPU: 107ms
      CGroup: /system.slice/hapee-3.3-lb.service
      ├─556 /opt/hapee-3.3/sbin/hapee-lb -Ws -f /etc/hapee-3.3/hapee-lb.cfg -p /run/hapee-3.3-lb.pid -S /run/hapee-lb-master.sock
      └─584 /opt/hapee-3.3/sbin/hapee-lb -Ws -f /etc/hapee-3.3/hapee-lb.cfg -p /run/hapee-3.3-lb.pid -S /run/hapee-lb-master.sock
      output
      text
      ● hapee-3.3-lb.service - HAPEE Load Balancer
      Loaded: loaded (/usr/lib/systemd/system/hapee-3.3-lb.service; enabled; preset: enabled)
      Active: active (running) since Tue 2026-05-12 14:30:38 UTC; 39min ago
      Main PID: 556 (hapee-lb)
      Status: "Ready."
      Tasks: 3 (limit: 4520)
      Memory: 26.1M (peak: 26.5M)
      CPU: 107ms
      CGroup: /system.slice/hapee-3.3-lb.service
      ├─556 /opt/hapee-3.3/sbin/hapee-lb -Ws -f /etc/hapee-3.3/hapee-lb.cfg -p /run/hapee-3.3-lb.pid -S /run/hapee-lb-master.sock
      └─584 /opt/hapee-3.3/sbin/hapee-lb -Ws -f /etc/hapee-3.3/hapee-lb.cfg -p /run/hapee-3.3-lb.pid -S /run/hapee-lb-master.sock
    • Edit the HAProxy Data Plane API configuration file. On HAProxy, it’s located at /etc/dataplaneapi/dataplaneapi.yml. On HAProxy Enterprise, it’s located at /etc/hapee-extras/dataplaneapi.yml. Under the haproxy section, set the master_runtime field to the HAProxy master socket path. For example:

      dataplaneapi.yml
      yaml
      haproxy:
      master_runtime: /run/haproxy-master.sock
      dataplaneapi.yml
      yaml
      haproxy:
      master_runtime: /run/haproxy-master.sock
    • Restart the HAProxy Data Plane API.

      nix
      sudo systemctl restart dataplaneapi
      nix
      sudo systemctl restart dataplaneapi
      nix
      sudo systemctl restart hapee-extras-dataplaneapi
      nix
      sudo systemctl restart hapee-extras-dataplaneapi
  3. Edit your load balancer configuration accordingly:

    • In the global section, add expose-experimental-directives and httpclient.resolvers.prefer ipv4:

      haproxy
      global
      ...
      expose-experimental-directives
      httpclient.resolvers.prefer ipv4
      haproxy
      global
      ...
      expose-experimental-directives
      httpclient.resolvers.prefer ipv4
    • After the global section, add an acme section to register with Let’s Encrypt. In this example, we’re using the Let’s Encrypt staging server, which you can use for testing. Later, change it to the Let’s Encrypt production server.

      haproxy
      acme letsencrypt-staging
      directory https://acme-staging-v02.api.letsencrypt.org/directory
      contact admin@example.com
      challenge HTTP-01
      map virt@acme
      haproxy
      acme letsencrypt-staging
      directory https://acme-staging-v02.api.letsencrypt.org/directory
      contact admin@example.com
      challenge HTTP-01
      map virt@acme
    • After the acme section, add a crt-store section to define the location of your Let’s Encrypt issued certificate. You don’t have to use a crt-store section. For small configurations, the arguments can all go onto the ssl-f-use line. The load directive will save the .pem certificate, after it’s generated, to the specified crt-base directory. Change this line to use your domain.

      haproxy
      crt-store my_files
      crt-base /etc/haproxy/ssl
      key-base /etc/haproxy/ssl
      load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example"
      haproxy
      crt-store my_files
      crt-base /etc/haproxy/ssl
      key-base /etc/haproxy/ssl
      load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example"
      haproxy
      crt-store my_files
      crt-base /etc/hapee-3.3/ssl
      key-base /etc/hapee-3.3/ssl
      load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example"
      haproxy
      crt-store my_files
      crt-base /etc/hapee-3.3/ssl
      key-base /etc/hapee-3.3/ssl
      load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example"
    • In your frontend section, respond to the Let’s Encrypt challenge via the http-request return directive and use the ssl-f-use directive to serve the TLS certificate bundle.

      haproxy
      frontend mysite
      bind :80
      bind :443 ssl
      http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].%[path,field(-1,/),map(virt@acme)]\n" if { path_beg '/.well-known/acme-challenge/' }
      http-request redirect scheme https unless { ssl_fc }
      ssl-f-use crt "@my_files/example"
      use_backend webservers
      haproxy
      frontend mysite
      bind :80
      bind :443 ssl
      http-request return status 200 content-type text/plain lf-string "%[path,field(-1,/)].%[path,field(-1,/),map(virt@acme)]\n" if { path_beg '/.well-known/acme-challenge/' }
      http-request redirect scheme https unless { ssl_fc }
      ssl-f-use crt "@my_files/example"
      use_backend webservers
  4. Restart the load balancer.

    nix
    sudo systemctl restart haproxy
    nix
    sudo systemctl restart haproxy
    nix
    sudo systemctl restart hapee-3.3-lb
    nix
    sudo systemctl restart hapee-3.3-lb
  5. HAProxy 3.2 / HAProxy Enterprise 3.2: Use the HAProxy Runtime API to initiate getting a certificate. In newer versions, this happens automatically when you restart the load balancer.

    • Call the Runtime API command acme renew to create a Let’s Encrypt certificate that replaces, in memory, the dummy TLS certificate file you created earlier.

      nix
      echo "acme renew @my_files/example" | sudo socat stdio tcp4-connect:127.0.0.1:9999
      nix
      echo "acme renew @my_files/example" | sudo socat stdio tcp4-connect:127.0.0.1:9999
    • The new certificate exists only in the load balancer’s running memory. To save it to a file, call the Runtime API command dump ssl cert.

      nix
      echo "dump ssl cert @my_files/example" | sudo socat stdio tcp4-connect:127.0.0.1:9999 | sudo tee /etc/haproxy/example.pem
      nix
      echo "dump ssl cert @my_files/example" | sudo socat stdio tcp4-connect:127.0.0.1:9999 | sudo tee /etc/haproxy/example.pem
    • Use the Runtime API command acme status to see a list of running tasks.

      nix
      echo "acme status" | sudo socat stdio tcp4-connect:127.0.0.1:9999
      nix
      echo "acme status" | sudo socat stdio tcp4-connect:127.0.0.1:9999
      output
      text
      # certificate section state expiration date (UTC) expires in scheduled date (UTC) scheduled in
      @my_files/example letsencrypt-staging Running 2026-09-30T20:37:44Z 364d 23h50m02s - -
      output
      text
      # certificate section state expiration date (UTC) expires in scheduled date (UTC) scheduled in
      @my_files/example letsencrypt-staging Running 2026-09-30T20:37:44Z 364d 23h50m02s - -

The TLS certificate should now be saved to the /etc/haproxy/ssl directory. It will be used when clients make requests to your domain.

DNS-01 challenge Jump to heading

This section applies to:

  • HAProxy 3.3 and newer
  • HAProxy Enterprise 3.3r1 and newer

We’ll use a DNS-01 challenge type. The challenge allows the Let’s Encrypt servers to verify that you control the domain for which you’re requesting a certificate. In this case, HAProxy hosts a TXT record at the DNS server that answers for your domain, which Let’s Encrypt verifies.

Through the Golang libdns library, we support these DNS providers:

DNS providers
Provider Arguments
azure
  • subscription_id (required)
  • resource_group_name (required)
  • tenant_id
  • client_id
  • client_secret
cloudflare
  • api_token (required)
  • zone_token
cloudns
  • auth_id
  • sub_auth_id
  • auth_password
digitalocean
  • auth_token
exec
  • command
gandi
  • bearer_token
godaddy
  • api_token
googleclouddns
  • gcp_project
  • gcp_project
hetzner
  • auth_api_token
infomaniak
  • api_token
inwx
  • username
  • password
  • shared_secret
  • endpoint_url
ionos
  • auth_api_token
linode
  • api_token
  • api_url
  • api_version
namecheap
  • api_key
  • user
  • api_endpoint
  • client_ip
netcup
  • customer_number
  • api_key
  • api_password
ovh
  • endpoint
  • application_key
  • application_secret
  • consumer_key
porkbun
  • api_key
  • api_secret_key
rfc2136
  • key_name
  • key_alg
  • key
  • server
route53
  • region
  • profile
  • access_key_id
  • secret_access_key
  • session_token
  • hosted_zone_id
scaleway
  • secret_key
  • organization_id
vultr
  • api_token

To get a certificate from Let’s Encrypt:

  1. HAProxy generates event notifications when it creates or updates a certificate from an ACME provider and the HAProxy Data Plane API watches for these events. Together, they automate saving the certificates to the filesystem.

    • Install the HAProxy Data Plane API.

    • Find the path to the HAProxy master socket, by calling systemctl status to get the value of the -S parameter.

      nix
      sudo systemctl status haproxy
      nix
      sudo systemctl status haproxy
      output
      text
      ● haproxy.service - HAProxy Load Balancer
      Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; preset: enabled)
      Active: active (running) since Mon 2026-04-06 14:39:32 UTC; 33min ago
      Docs: man:haproxy(1)
      file:/usr/share/doc/haproxy/configuration.txt.gz
      Main PID: 2366 (haproxy)
      Status: "Ready."
      Tasks: 3 (limit: 9433)
      Memory: 69.2M (peak: 70.8M)
      CPU: 63ms
      CGroup: /system.slice/haproxy.service
      ├─2366 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
      └─2368 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
      output
      text
      ● haproxy.service - HAProxy Load Balancer
      Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; preset: enabled)
      Active: active (running) since Mon 2026-04-06 14:39:32 UTC; 33min ago
      Docs: man:haproxy(1)
      file:/usr/share/doc/haproxy/configuration.txt.gz
      Main PID: 2366 (haproxy)
      Status: "Ready."
      Tasks: 3 (limit: 9433)
      Memory: 69.2M (peak: 70.8M)
      CPU: 63ms
      CGroup: /system.slice/haproxy.service
      ├─2366 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
      └─2368 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -S /run/haproxy-master.sock
      nix
      sudo systemctl status hapee-3.3-lb
      nix
      sudo systemctl status hapee-3.3-lb
      output
      text
      ● hapee-3.3-lb.service - HAPEE Load Balancer
      Loaded: loaded (/usr/lib/systemd/system/hapee-3.3-lb.service; enabled; preset: enabled)
      Active: active (running) since Tue 2026-05-12 14:30:38 UTC; 39min ago
      Main PID: 556 (hapee-lb)
      Status: "Ready."
      Tasks: 3 (limit: 4520)
      Memory: 26.1M (peak: 26.5M)
      CPU: 107ms
      CGroup: /system.slice/hapee-3.3-lb.service
      ├─556 /opt/hapee-3.3/sbin/hapee-lb -Ws -f /etc/hapee-3.3/hapee-lb.cfg -p /run/hapee-3.3-lb.pid -S /run/hapee-lb-master.sock
      └─584 /opt/hapee-3.3/sbin/hapee-lb -Ws -f /etc/hapee-3.3/hapee-lb.cfg -p /run/hapee-3.3-lb.pid -S /run/hapee-lb-master.sock
      output
      text
      ● hapee-3.3-lb.service - HAPEE Load Balancer
      Loaded: loaded (/usr/lib/systemd/system/hapee-3.3-lb.service; enabled; preset: enabled)
      Active: active (running) since Tue 2026-05-12 14:30:38 UTC; 39min ago
      Main PID: 556 (hapee-lb)
      Status: "Ready."
      Tasks: 3 (limit: 4520)
      Memory: 26.1M (peak: 26.5M)
      CPU: 107ms
      CGroup: /system.slice/hapee-3.3-lb.service
      ├─556 /opt/hapee-3.3/sbin/hapee-lb -Ws -f /etc/hapee-3.3/hapee-lb.cfg -p /run/hapee-3.3-lb.pid -S /run/hapee-lb-master.sock
      └─584 /opt/hapee-3.3/sbin/hapee-lb -Ws -f /etc/hapee-3.3/hapee-lb.cfg -p /run/hapee-3.3-lb.pid -S /run/hapee-lb-master.sock
    • Edit the HAProxy Data Plane API configuration file. On HAProxy, it’s /etc/dataplaneapi/dataplaneapi.yml. On HAProxy Enterprise, it’s /etc/hapee-extras/dataplaneapi.yml. Under the haproxy section, set the master_runtime field to the HAProxy master socket path. For example:

      dataplaneapi.yml
      yaml
      haproxy:
      master_runtime: /run/haproxy-master.sock`
      dataplaneapi.yml
      yaml
      haproxy:
      master_runtime: /run/haproxy-master.sock`
    • Restart the HAProxy Data Plane API.

      nix
      sudo systemctl restart dataplaneapi
      nix
      sudo systemctl restart dataplaneapi
      nix
      sudo systemctl restart hapee-extras-dataplaneapi
      nix
      sudo systemctl restart hapee-extras-dataplaneapi
  2. Edit your load balancer configuration:

    • In the global section, add expose-experimental-directives and httpclient.resolvers.prefer ipv4:

      haproxy
      global
      ...
      expose-experimental-directives
      httpclient.resolvers.prefer ipv4
      haproxy
      global
      ...
      expose-experimental-directives
      httpclient.resolvers.prefer ipv4
    • After the global section, add an acme section to register with Let’s Encrypt. In this example, we’re using the Let’s Encrypt staging server, which you can use for testing. Later, change it to the Let’s Encrypt production server. This example uses the azure DNS provider. Your acme section should define the variables listed for your provider, listed earlier in this section.

      haproxy
      acme letsencrypt-staging
      directory https://acme-staging-v02.api.letsencrypt.org/directory
      contact admin@example.com
      challenge DNS-01
      provider-name azure
      acme-vars "subscription_id=abcd1234-7f9f-4cc1-bcd0-025d68911156, resource_group_name=myresourcegroup, tenant_id=aaaaaaaa-bc90-49cc-8fef-1260b982dfe6, client_id=d5adf5ec-50af-4c3b-b86d-29059f5936bd, client_secret=LRE8Q~Z5ZPlPdm6m7vdrui1Il8z-hqFCpPj0HarM"
      haproxy
      acme letsencrypt-staging
      directory https://acme-staging-v02.api.letsencrypt.org/directory
      contact admin@example.com
      challenge DNS-01
      provider-name azure
      acme-vars "subscription_id=abcd1234-7f9f-4cc1-bcd0-025d68911156, resource_group_name=myresourcegroup, tenant_id=aaaaaaaa-bc90-49cc-8fef-1260b982dfe6, client_id=d5adf5ec-50af-4c3b-b86d-29059f5936bd, client_secret=LRE8Q~Z5ZPlPdm6m7vdrui1Il8z-hqFCpPj0HarM"
    • After the acme section, add a crt-store section to define the location of your Let’s Encrypt issued certificate. You don’t have to use a crt-store section. For small configurations, the arguments can all go onto the ssl-f-use line. The load directive will save the .pem certificate, after it’s generated, to the specified crt-base directory. Change this line to use your domain.

      haproxy
      crt-store my_files
      crt-base /etc/haproxy/ssl
      key-base /etc/haproxy/ssl
      load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example"
      haproxy
      crt-store my_files
      crt-base /etc/haproxy/ssl
      key-base /etc/haproxy/ssl
      load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example"
      haproxy
      crt-store my_files
      crt-base /etc/hapee-3.3/ssl
      key-base /etc/hapee-3.3/ssl
      load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example"
      haproxy
      crt-store my_files
      crt-base /etc/hapee-3.3/ssl
      key-base /etc/hapee-3.3/ssl
      load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example"
    • In your frontend section, use the ssl-f-use directive to serve the TLS certificate bundle.

      haproxy
      frontend mysite
      bind :80
      bind :443 ssl
      http-request redirect scheme https unless { ssl_fc }
      ssl-f-use crt "@my_files/example"
      use_backend webservers
      haproxy
      frontend mysite
      bind :80
      bind :443 ssl
      http-request redirect scheme https unless { ssl_fc }
      ssl-f-use crt "@my_files/example"
      use_backend webservers
  3. Restart the load balancer.

    nix
    sudo systemctl restart haproxy
    nix
    sudo systemctl restart haproxy
    nix
    sudo systemctl restart hapee-3.3-lb
    nix
    sudo systemctl restart hapee-3.3-lb

Set an ACME profile Jump to heading

This section applies to:

  • HAProxy 3.4 and newer

The acme configuration section supports a profile directive that implements the ACME Profiles Extension. An ACME profile indicates the specific certificate you’d like to get from the certificate authority (CA). The options offered by a CA will determine what values you define. Let’s Encrypt offers several ACME profiles, showcased below:

  • classic; the default profile if none is defined.
  • tlsserver; this profile reflects the latest recommendations from the CA/Browser Forum Baseline Requirements, as well as general trends within the WebPKI community. Let’s Encrypt recommends selecting this profile for subscribers who want smaller certificates and who fully embrace automation. See details in Let’s Encrypt tlsserver.
  • shortlived; this profile is the same as the tlsserver profile but with a resulting certificate valid for about 6 days instead. See details in Let’s Encrypt shortlived.

If your use case stipulates in selecting a profile, here’s how to set an ACME profile:

  1. Edit your load balancer configuration accordingly. In this example, we’re using the Let’s Encrypt staging server with an HTTP-01 challenge, which you can use for testing. Later, change it to the Let’s Encrypt production server. We’re setting the ACME profile to tlsserver:

    haproxy
    acme letsencrypt-staging
    directory https://acme-staging-v02.api.letsencrypt.org/directory
    contact admin@example.com
    challenge HTTP-01
    map virt@acme
    profile tlsserver
    haproxy
    acme letsencrypt-staging
    directory https://acme-staging-v02.api.letsencrypt.org/directory
    contact admin@example.com
    challenge HTTP-01
    map virt@acme
    profile tlsserver
  2. Restart the load balancer with:

    nix
    sudo systemctl restart haproxy
    nix
    sudo systemctl restart haproxy

Set the Subject Alternative Name to an IP address Jump to heading

This section applies to:

  • HAProxy 3.4 and newer

Set IP addresses in the Subject Alternative Name field in ACME-generated certificates by configuring the load directive’s ips argument in your crt-store section:

  1. Edit your load balancer configuration accordingly. After the acme section, add a crt-store section (if you don’t already have one) to define the location of your Let’s Encrypt issued certificate. The load directive will save the .pem certificate, after it’s generated, to the specified crt-base directory. Change this line to use your domain and IP addresses (multiple IP addresses are separated by commas inside the string):

    haproxy
    crt-store my_files
    crt-base /etc/haproxy/ssl
    key-base /etc/haproxy/ssl
    load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example" ips "192.0.2.1,2001:db8::1"
    haproxy
    crt-store my_files
    crt-base /etc/haproxy/ssl
    key-base /etc/haproxy/ssl
    load crt "example.pem" acme letsencrypt-staging domains "www.example.com" alias "example" ips "192.0.2.1,2001:db8::1"
  2. Restart the load balancer with:

    nix
    sudo systemctl restart haproxy
    nix
    sudo systemctl restart haproxy

Enable External Account Binding Jump to heading

This section applies to:

  • HAProxy 3.4 and newer

An ACME External Account Binding (EAB) aims to protect your ACME account from unauthorized access. During your initial ACME account creation with a CA, you will get two EAB credentials: the EAB key ID and MAC key. You can enable EAB in HAProxy using these directives:

  • eab-key-id; configure the path to the EAB key ID file. The key ID credential is provided by the CA and must be placed at the specified path before starting HAProxy. It’s used during account creation only. The file must contain a plain ASCII string.
  • eab-mac-key; configure the path to the EAB MAC key file. The MAC key credential is provided by the CA and must be placed at the specified path before starting HAProxy. It’s used during account creation only. The file must contain a base64url encoded MAC key.
  • eab-mac-alg; configure the MAC algorithm used for EAB signing. The default is HS256, and the other configurable values are HS384 or HS512. The EAB MAC key must be large enough to support the specified MAC algorithm. Not all CAs support algorithms other than HS256.

For example, we stored the EAB key ID in a text file at /etc/haproxy/eab_key_id.txt and the EAB MAC key in a text file at /etc/haproxy/eab_mac_key.txt. Our example EAB MAC key is large enough to support HS512, so we configured the MAC algorithm to use HS512:

haproxy
acme staging-example
...
eab-key-id /etc/haproxy/eab_key_id.txt
eab-mac-key /etc/haproxy/eab_mac_key.txt
eab-mac-alg HS512
haproxy
acme staging-example
...
eab-key-id /etc/haproxy/eab_key_id.txt
eab-mac-key /etc/haproxy/eab_mac_key.txt
eab-mac-alg HS512

See also Jump to heading

Reference the HAProxy Configuration Manual for more information about the:

See the HAProxy Wiki tutorial on GitHub for ACME.

Do you have any suggestions on how we can improve the content of this page?