Zero downtime with Let's Encrypt

Introduction

Apparently there is no way to define an alternative port for Let's Encrypt verification process. ACME specification states explicitly that those must be 80 and 443 ports.

Thus, with production servers running, you either have to tolerate downtime or let Let's Encrypt client tamper with your precious configs. None of both is very desirable.

Opposite to the official client, lego client lets you define a custom port, you can then redirect the verification traffic to. And here is, how I done it.

/etc/pf.conf

First, lets redirect requests from special IP's to 80 and 443 to another port (8443 in my case).

table <letsencrypt> persist file "/etc/letsencrypt.pf"

pass in quick inet proto tcp from <letsencrypt> \
    to port {http, https} rdr-to egress port 8443

Please note, that we are redirecting to external IP (egress interface), since there is no way to tell lego to listen on localhost. You can only define a custom port.

/etc/letsecnrypt.pf

This file contains special URIs, where verification requests are coming from. The first two entries are important. The other two are only for completeness sake here.

outbound1.letsencrypt.org
outbound2.letsencrypt.org

acme-staging.api.letsencrypt.org
acme-v01.api.letsencrypt.org

IPs get resolved and loaded into letsencrypt table automaticly. Or load it manually

pfctl -tletsencrypt -Ta -f /etc/letsencrypt.pf

Beware: those IPs may change frequently. I suggest you to reload them periodically.

lego

And now, the client

go get -u github.com/xenolf/lego
lego -m another@example.com --port 8443 -d example.com run

And that's all.

Conclusion

This setup has several benefits.

References

Similar solution for Linux

iptables --table nat --append PREROUTING --protocol tcp \
    --source <Validation Authority IP address> --dport 443 \
    --jump REDIRECT --to-ports <ACME client port>
By Dimitri Sokolyuk
Related articles