diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 410b595082..70087bee4b 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -810,6 +810,11 @@ kolla_verify_tls_backend: "yes"
 kolla_tls_backend_cert: "{{ kolla_certificates_dir }}/backend-cert.pem"
 kolla_tls_backend_key: "{{ kolla_certificates_dir }}/backend-key.pem"
 
+#####################
+# ACME client options
+#####################
+acme_client_servers: []
+
 ####################
 # Kibana options
 ####################
diff --git a/ansible/roles/horizon/defaults/main.yml b/ansible/roles/horizon/defaults/main.yml
index c8698b1b9c..6876cc37fa 100644
--- a/ansible/roles/horizon/defaults/main.yml
+++ b/ansible/roles/horizon/defaults/main.yml
@@ -44,6 +44,8 @@ horizon_services:
         external: false
         port: "{% if kolla_enable_tls_internal|bool %}{{ horizon_tls_port }}{% else %}{{ horizon_port }}{% endif %}"
         listen_port: "{{ horizon_listen_port }}"
+        frontend_http_extra:
+          - "use_backend acme_client_back if { path_reg ^/.well-known/acme-challenge/.+ }"
         backend_http_extra:
           - "balance source"
         tls_backend: "{{ horizon_enable_tls_backend }}"
@@ -59,6 +61,8 @@ horizon_services:
         external: true
         port: "{% if kolla_enable_tls_external|bool %}{{ horizon_tls_port }}{% else %}{{ horizon_port }}{% endif %}"
         listen_port: "{{ horizon_listen_port }}"
+        frontend_http_extra:
+          - "use_backend acme_client_back if { path_reg ^/.well-known/acme-challenge/.+ }"
         backend_http_extra:
           - "balance source"
         tls_backend: "{{ horizon_enable_tls_backend }}"
@@ -68,6 +72,11 @@ horizon_services:
         external: true
         port: "{{ horizon_port }}"
         listen_port: "{{ horizon_listen_port }}"
+      acme_client:
+        enabled: "{{ enable_horizon }}"
+        with_frontend: false
+        custom_member_list: "{{ acme_client_servers }}"
+
 horizon_keystone_domain_choices:
   Default: default
 
diff --git a/doc/source/admin/acme.rst b/doc/source/admin/acme.rst
new file mode 100644
index 0000000000..6a12efe11e
--- /dev/null
+++ b/doc/source/admin/acme.rst
@@ -0,0 +1,41 @@
+.. acme:
+
+==============================
+ACME http-01 challenge support
+==============================
+
+This guide describes how to configure Kolla Ansible to enable ACME http-01
+challenge support.
+As of Victoria, Kolla Ansible supports configuring HAProxy Horizon frontend
+to proxy ACME http-01 challenge requests to selected external (not deployed
+by Kolla Ansible) ACME client servers. These can be ad-hoc or regular servers.
+This guide assumes general knowledge of ACME.
+
+Do note ACME supports http-01 challenge only over official HTTP(S) ports, that
+is 80 (for HTTP) and 443 (for HTTPS). Only Horizon is normally deployed on such
+port with Kolla Ansible (other services use custom ports). This means that,
+as of now, running Horizon is mandatory to support ACME http-01 challenge.
+
+How To (External ACME client)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You need to determine the IP address (and port) of the ACME client server
+used for http-01 challenge (e.g. the host you use to run certbot).
+The default port is usually ``80`` (HTTP). Assuming the IP address of that host
+is ``192.168.1.1``, the config would look like the following:
+
+.. code-block:: yaml
+
+  enable_horizon: "yes"
+  acme_client_servers:
+    - server certbot 192.168.1.1:80
+
+``acme_client_servers`` is a list of HAProxy backend server directives. The
+first parameter is the name of the backend server - it can be arbitrary and
+is used for logging purposes.
+
+After (re)deploying, you can proceed with running the client to host the
+http-01 challenge files. Please ensure Horizon frontend responds on the domain
+you request the certificate for.
+
+To use the newly-generated key-cert pair, follow the :doc:`tls` guide.
diff --git a/doc/source/admin/index.rst b/doc/source/admin/index.rst
index eb7e906f87..720b663c3f 100644
--- a/doc/source/admin/index.rst
+++ b/doc/source/admin/index.rst
@@ -7,6 +7,7 @@ Admin Guides
 
    advanced-configuration
    tls
+   acme
    mariadb-backup-and-restore
    production-architecture-guide
    deployment-philosophy
diff --git a/doc/source/admin/tls.rst b/doc/source/admin/tls.rst
index eefca82477..2e619b512b 100644
--- a/doc/source/admin/tls.rst
+++ b/doc/source/admin/tls.rst
@@ -30,6 +30,9 @@ There are two different layers of TLS configuration for OpenStack APIs:
   :ref:`admin-tls-generating-a-private-ca` to use a Kolla Ansible generated
   private CA.
 
+  For details on ACME-enabled CAs, such as letsencrypt.org, please see
+  :doc:`acme`.
+
 Quick Start
 ~~~~~~~~~~~
 
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index bbe261afad..804f6eb7c8 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -223,6 +223,14 @@
 #kolla_tls_backend_cert: "{{ kolla_certificates_dir }}/backend-cert.pem"
 #kolla_tls_backend_key: "{{ kolla_certificates_dir }}/backend-key.pem"
 
+#####################
+# ACME client options
+#####################
+# A list of haproxy backend server directives pointing to addresses used by the
+# ACME client to complete http-01 challenge.
+# Please read the docs for more details.
+#acme_client_servers: []
+
 ################
 # Region options
 ################
diff --git a/releasenotes/notes/external-acme-client-support-cee19c4755e04eab.yaml b/releasenotes/notes/external-acme-client-support-cee19c4755e04eab.yaml
new file mode 100644
index 0000000000..827c7da5b7
--- /dev/null
+++ b/releasenotes/notes/external-acme-client-support-cee19c4755e04eab.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    Adds support for completing the http-01 challenge of ACME (e.g. as provided
+    by Let's Encrypt - letsencrypt.org) using an external ACME client
+    (e.g. certbot). The relevant variable is ``acme_client_servers``.
+    Please read the docs for more info on this integration.