Skip to content

TLS ALPN without downtime

andrewheberle edited this page Nov 23, 2019 · 6 revisions

Using TLS-ALPN without downtime added support for TLS-ALPN on 2018-12-28.

This feature allows domain validation to be performed over port 443, useful when port 80 is not accessible. However, the feature requires any existing webservers on that port to be shut down so that can listen on port 443.

This article outlines some ways it is possible to configure webservers to work transparently with's TLS-ALPN support without having to stop and start your webserver.


Webserver Status Caveats
Apache httpd Not possible Consider using mod_md, which is an Apache module that replaces It can perform TLS-ALPN validation since version 1.99.
nginx Supported Requires ngx_stream_ssl_preread_module to be compiled. e.g. on Ubuntu 18.04, included in the nginx-full package.
HAProxy Supported Requires HAProxy >= 1.9.1



With nginx, what we do is create a TLS-ALPN load balancer within nginx on port 443, and re-assign all existing HTTPS virtual hosts within nginx to another port.

When a TLS-ALPN connection comes in, it is routed to, otherwise, the connection is routed to the HTTPS virtual hosts.

1. Verify that nginx is compiled with the required module:

$ nginx -V 2>&1 | grep -o ssl_preread

2. Re-assign ALL port 443 virtual hosts to another port

If you have existing HTTPS virtual hosts listening on port 443, you will need to re-assign each HTTPS server to an alternate port (such as 8443), so that we can put the ALPN load balancer on port 443.

For example

server {
    listen 443;
    # ...

would become

server {
    listen 8443;
    # ...

3. Add the ALPN load balancer

In /etc/nginx.conf, at the end of the file, add (substituting 8443 for the port chosen in step 2):

stream {
  map $ssl_preread_alpn_protocols $tls_port {
    ~\bacme-tls/1\b 10443;
    default 8443;
  server {
    listen 443;
    listen [::]:443;
    ssl_preread on;

4. Make sure the configuration works and reload.

$ sudo nginx -t
$ sudo systemctl reload nginx

5. Try to issue a certificate (substituting for the domain you want on your certificate).

$ sudo --issue --alpn --tlsport 10443 -d


With HAProxy, what we have to do is run an ALPN load balancer frontend in TCP mode on port 443, and re-assign all HTTPS frontends to an alternate port.

When a TLS-ALPN connection for ACME comes in, it will be routed to, otherwise, the connection is forwarded to the normal HTTPS frontend.

1. Verify that HAProxy is at least version 1.9.1:

$ haproxy -v
HA-Proxy version 1.9.2 2019/01/16 -

2. In the HAProxy configuration, as well as re-assigning your existing HTTPS (443) frontend to port 8443, you will need to add:

  1. fe_alpn - a TCP frontend on 443 to load balance ALPN
  2. bk_acmesh - A backend to send requests to
  3. bk_https - A backend to send requests to your regular HTTPS frontend

In this example the PROXY protocol is used between bk_https and fe_https so the original clients source IP is known.

# New
frontend fe_alpn
  mode tcp
  bind :443
  tcp-request inspect-delay 5s
  tcp-request content accept if { req_ssl_hello_type 1 }
  use_backend bk_acmesh if { req.ssl_alpn acme-tls/1 }
  default_backend bk_https

# New
backend bk_acmesh
  server acmesh

# New
backend bk_https
  server https send-proxy-v2

# Existing, changed from :443 ->
frontend fe_https
  mode http
  bind ssl crt /etc/ssl/haproxy.pem accept-proxy
  # ...

3. Make sure the configuration works and reload:

$ sudo haproxy -c -f /etc/haproxy.cfg
$ sudo systemctl reload haproxy

4. Try to issue a certificate (substituting for the domain you want on your certificate).

$ sudo --issue --alpn --tlsport 10443 -d
You can’t perform that action at this time.