diff options
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.html | 256 |
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> |