summaryrefslogtreecommitdiff
path: root/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html
diff options
context:
space:
mode:
Diffstat (limited to 'posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html')
-rw-r--r--posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html256
1 files changed, 0 insertions, 256 deletions
diff --git a/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html b/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html
deleted file mode 100644
index 34fbcf0..0000000
--- a/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html
+++ /dev/null
@@ -1,256 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="How to Automate Certbot Renewal with HAProxy"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ How to Automate Certbot Renewal with HAProxy</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>How to Automate Certbot Renewal with HAProxy</h1>
-
- <p>
- So this is specifically for HAProxy on FreeBSD, but it should apply to
- other *nix systems as well. Basically, I use HAProxy as a reverse proxy
- to a bunch of servers I administer. I use Let's Encrypt for a
- certificate and I used <code>certbot</code> to generate that
- certificate. Generating the certificate for the first time is easy and
- has lots of documentation, but it wasn't initially clear on how I could
- easily set up auto-renewal. Here's how I did it.
- </p>
-
- <p>
- If you've already set up TLS termination with HAProxy and
- <code>certbot</code>, you know you need to combine your Let's Encrypt
- fullchain and private key to get a combined certificate that HAProxy can
- use. You can do this by <code>cat</code>-ing the chain and key together
- like so:
- </p>
-
- <pre>
-<code>
-cat /usr/local/etc/letsencrypt/live/$SITE/fullchain.pem /usr/local/etc/letsencrypt/live/$SITE/privkey.pem > /usr/local/etc/ssl/haproxy.pem
-</code>
- </pre>
-
- <p>
- In this example, <code>$SITE</code> is your domain name that you fed
- HAProxy when you created the certificate and <code>haproxy.pem</code> is
- wherever you're storing HAProxy's combined certificate. Your HAProxy
- config then points to that certificate like this:
- </p>
-
- <pre>
-<code>
-macon% grep crt /usr/local/etc/haproxy.conf
- bind *:443 ssl crt /usr/local/etc/ssl/haproxy.pem
-</code>
- </pre>
-
- <p>
- And that was the end of the first-time setup. Then a few months later
- you probably had to do it again because Let's Encrypt certs are only
- good for 90 days in between renewals. To renew the certificate, you
- usually run <code>certbot renew</code>, it detects which certificates
- are present, and uses either the webroot or standlone server renewal
- process. Then you have to <code>cat</code> the fullchain and privkey
- together and restart HAProxy so it starts using the new certificate.
- </p>
-
- <p>
- To automate those steps, newer versions of
- <code>certbot</code> will run any post renewal hooks (read: scripts)
- that you want. You can also configure HAProxy and
- <code>certbot</code> to perform the ACME challenge dance for renewal so
- that you don't have to use it interactively.
- </p>
-
- <p>
- First, if you haven't already done it, change your HAProxy config so
- there's a frontend+backend for responding to ACME challenges. In a
- frontend listening for requests, create an access control list for any
- request looking for <code>/.well-known/acme-challenge/</code>. Send
- those requests to a backend server with an unused local port.
- </p>
-
- <pre>
-<code>
-frontend http-in
- acl letsencrypt-acl path_beg /.well-known/acme-challenge/
- use_backend letsencrypt-backend if letsencrypt-acl
- ...
-backend letsencrypt-backend
- server letsencrypt 127.0.0.1:54321
-</code>
- </pre>
-
- <p>
- What this will do is allow <code>certbot</code> and Let's Encrypt to
- renew your server in standalone mode via your reverse proxy. As an added
- bonus it prevents you from having to open up an additional port on your
- firewall.
- </p>
-
- <p>
- Now you've gotta configure <code>certbot</code> to do just that. A
- config file was created in <code>certbot</code>'s
- <code>renew</code> directory for your site. All you need to do in that
- file is add a line to the <code>[renewalparams]</code> section
- specifying the port you're using in your HAProxy config.
- </p>
-
- <pre>
-<code>
-macon% echo "http01_port = 54321" >> /usr/local/etc/letsencrypt/renewal/$SITE.conf
-</code>
- </pre>
-
- <p>
- Now you need the post-renewal hooks. I dropped two separate scripts into
- the <code>renewal-hooks</code> directory: one does the job of combining
- the certificate chain and private key and the other just restarts
- HAProxy.
- </p>
-
- <pre>
-<code>
-macon% cat /usr/local/etc/letsencrypt/renewal-hooks/post/001-catcerts.sh
-#!/bin/sh
-
-SITE=(your site of course)
-
-cd /usr/local/etc/letsencrypt/live/$SITE
-cat fullchain.pem privkey.pem > /usr/local/etc/ssl/haproxy.pem
-macon% cat /usr/local/etc/letsencrypt/renewal-hooks/post/002-haproxy.sh
-#!/bin/sh
-service haproxy restart
-</code>
- </pre>
-
- <p>
- When <code>certbot renew</code> is run, <code>certbot</code> checks the
- <code>renewal-hooks/post</code> directory and runs any executable things
- in it after it's renewed the certificate(s). As a side note,
- <em>make sure you hit those scripts with <code>chmod +x</code></em> or
- they probably won't run.
- </p>
-
- <p>
- Now all that's left is dropping a job into <code>cron</code> or
- <code>periodic</code> to run <code>certbot renew</code> at least once or
- twice within the renewal period.
- </p>
-
- <pre>
-<code>
-macon% doas crontab -l|grep certbot
-# certbot renewal
-@monthly certbot renew
-</code>
- </pre>
-
- <p>
- You can always test that your scripts are working with
- <code>certbot renew --dry-run</code> just to be safe.
- </p>
-
- <pre>
-<code>
-macon% doas certbot renew --dry-run
-Saving debug log to /var/log/letsencrypt/letsencrypt.log
-
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Processing /usr/local/etc/letsencrypt/renewal/53hor.net.conf
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Cert not due for renewal, but simulating renewal for dry run
-Plugins selected: Authenticator standalone, Installer None
-Simulating renewal of an existing certificate for 53hor.net and 7 more domains
-Performing the following challenges:
-http-01 challenge for 53hor.net
-http-01 challenge for carpentertutoring.com
-http-01 challenge for git.53hor.net
-http-01 challenge for nextcloud.53hor.net
-http-01 challenge for pkg.53hor.net
-http-01 challenge for plex.53hor.net
-http-01 challenge for theglassyladies.com
-http-01 challenge for www.53hor.net
-Waiting for verification...
-Cleaning up challenges
-
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-new certificate deployed without reload, fullchain is
-/usr/local/etc/letsencrypt/live/53hor.net/fullchain.pem
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Congratulations, all simulated renewals succeeded:
- /usr/local/etc/letsencrypt/live/53hor.net/fullchain.pem (success)
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Running post-hook command: /usr/local/etc/letsencrypt/renewal-hooks/post/001-catcerts.sh
-Running post-hook command: /usr/local/etc/letsencrypt/renewal-hooks/post/002-haproxy.sh
-Output from post-hook command 002-haproxy.sh:
-Waiting for PIDS: 15191.
-Starting haproxy.
-
-</code>
- </pre>
-
- <p>
- And there it is. Automated Let's Encrypt certificate renewal on FreeBSD
- with HAProxy.
- </p>
- </article>
- </body>
-</html>