summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam T. Carpenter <atc@53hor.net>2021-03-19 16:07:55 -0400
committerAdam T. Carpenter <atc@53hor.net>2021-03-19 16:07:55 -0400
commitb477015b087cb5884029830873b66d273c99dbc9 (patch)
tree2e59b9352c6814cb6909f0afb7e582bbf307be04
parent51239223cbc8870caf0d72497e90069acf5adce5 (diff)
download53hor-b477015b087cb5884029830873b66d273c99dbc9.tar.xz
53hor-b477015b087cb5884029830873b66d273c99dbc9.zip
published certbot haproxy renewal, added/updated a bunch of drafts and CV
-rw-r--r--cv.html126
-rw-r--r--drafts/html-for-docs-2020.html8
-rw-r--r--drafts/it's not rust vs go.html49
-rw-r--r--drafts/make-your-web-site-look-boring.html2
-rw-r--r--drafts/my web site has no runtime.html1
-rw-r--r--index.html1
-rw-r--r--info.html29
-rw-r--r--posts/unix/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html256
-rw-r--r--rss.xml1
9 files changed, 346 insertions, 127 deletions
diff --git a/cv.html b/cv.html
index 687794b..ab4318f 100644
--- a/cv.html
+++ b/cv.html
@@ -6,9 +6,6 @@
<body>
<h1>Adam T. Carpenter</h1>
- <hr />
- <h2>Contact</h2>
-
<label for="email">Email</label>
<a id="email" href="mailto:atc@53hor.net">atc@53hor.net</a>
<label for="www">WWW</label>
@@ -19,7 +16,7 @@
<a id="git" href="https://git.53hor.net">git.53hor.net</a>
<p>
- This curriculum vitae is available in
+ This document is available in
<a href="https://www.53hor.net/cv.html">HTML</a> or as a
<a href="https://www.53hor.net/cv.pdf">PDF</a>.
</p>
@@ -27,29 +24,41 @@
<hr />
<h2>Summary</h2>
- <p>TODO:</p>
+ <p>
+ I am a computer programmer who has been developing and maintaining web
+ applications and services since 2018. I have also been providing systems
+ administration services and technical learning assistance since 2016.
+ </p>
+
+ <p>
+ I am fluent in Rust, C#, Python, JavaScript, Bourne Shell, and HTML. I am
+ also familiar with Java, PHP, C, C++, TypeScript, and PowerShell.
+ </p>
+
+ <hr />
+ <h2>Skills</h2>
+
+ <h3>Software Development</h3>
+ <h3>Systems Administration</h3>
+ <h3>Technical Leadership</h3>
<hr />
- <h2>Work Experience</h2>
+ <h2>Experience</h2>
<ul>
<li>
- Application Developer at Automatic Data Processing (Jun. 2018 to
- Present)
+ Automatic Data Processing | Application Developer | June 2018 to present
</li>
<li>
- Freelance Web Application Designer and Developer (Jul. 2019 to Present)
+ Freelance | Web Application Designer & Developer | July 2019 to present
</li>
<li>
- Technology Support Specialist at The College of William and Mary (Feb.
- 2015 to May 2018)
+ The College of William and Mary | Technology Support Specialist |
+ February 2015 to May 2018
</li>
</ul>
<hr />
- <h2>Skills</h2>
-
- <hr />
<h2>Academics</h2>
<ul>
@@ -62,94 +71,5 @@
2014)
</li>
</ul>
-
- <hr />
- <h2>Functional Skills and Qualifications</h2>
-
- <ul>
- Proficient Languages (Every Day)
- <li>Bourne Shell (POSIX <code>sh</code>)</li>
- <li>C#</li>
- <li>HTML, CSS</li>
- <li>Java</li>
- <li>JavaScript, ECMAScript</li>
- <li>Python</li>
- <li>Rust</li>
- </ul>
-
- <ul>
- Familiar Languages (Every So Often)
- <li>C++</li>
- <li>C</li>
- <li>TypeScript</li>
- <li>PowerShell</li>
- <li>PHP</li>
- </ul>
-
- <ul>
- Libraries & Frameworks
- <li>.NET Core, ASP.NET Core, EF Core</li>
- <li>Vue.js</li>
- <li>Aurelia</li>
- <li>Hyper.rs</li>
- <li>Actix.rs</li>
- <li>Spring Boot</li>
- <li>Symfony 5</li>
- </ul>
-
- <ul>
- Servers & Storage
- <li>Apache, NGINX, Lighttpd</li>
- <li>IIS</li>
- <li>MS SQL Server</li>
- <li>SQLite</li>
- <li>ZFS</li>
- <li>MongoDB</li>
- </ul>
-
- <ul>
- Platforms, Operating Systems, Virtualization
- <li>FreeBSD, jails</li>
- <li>
- Linux
- <ul>
- <li>Alpine Linux</li>
- <li>Arch, Manjaro GNU/Linux</li>
- <li>Debian GNU/Linux</li>
- </ul>
- </li>
- <li>Docker, Docker Swarm</li>
- <li>Kubernetes, IBM Cloud Private, Ferris Wheel, Helm</li>
- <li>Microsoft Windows 10, Windows Server 2016</li>
- </ul>
-
- <ul>
- Voice Vendor Technologies (from an automation perspective)
- <li>Avaya Communication Manager</li>
- <li>Genesys Call Routing, Configuration Server</li>
- <li>Calabrio Call Recording</li>
- <li>Glance CoBrowser</li>
- <li>VeraSMART Call Accounting</li>
- </ul>
-
- <ul>
- VCS, CI/CD
- <li>Git</li>
- <li>Subversion</li>
- <li>GitHub</li>
- <li>GitLab</li>
- <li>Bitbucket</li>
- <li>Jenkins</li>
- </ul>
-
- <ul>
- Text Processing & The Command Line
- <p>
- The tools I use day-to-day on the command line are too numerous to list
- here. I'm frequently jotting notes about what I use on my web log, and
- maintain/update a post on what I frequently use there as well. TODO:
- link
- </p>
- </ul>
</body>
</html>
diff --git a/drafts/html-for-docs-2020.html b/drafts/html-for-docs-2020.html
index 3e7adee..a33bb51 100644
--- a/drafts/html-for-docs-2020.html
+++ b/drafts/html-for-docs-2020.html
@@ -10,3 +10,11 @@
web browser installed - Anyone can print out an HTML document - Anyone can edit
an HTML document - Writing a document in HTML is easier than writing one in Word
or Latex
+
+<p>
+ I've been without Word for a few years since I switched away from Windows and
+ honestly I haven't needed it. I took notes and wrote documents in Markdown for
+ a while. That was alright because the syntax is easy and any text editor can
+ read a Markdown file. Recently however, I've started using HTML for writing
+ documents that I intend to upload, print, or send to other users. Here's why.
+</p>
diff --git a/drafts/it's not rust vs go.html b/drafts/it's not rust vs go.html
index 8b3d6fc..6826d55 100644
--- a/drafts/it's not rust vs go.html
+++ b/drafts/it's not rust vs go.html
@@ -1,6 +1,6 @@
-<h1>It's Not Rust VS Go</h1>
-
-include coworker conversation tidbits draft notes:
+<h1>"Rust or Go?" is not the question</h1>
+<h1>Part 2: (But Rust is definitely the answer)</h1>
+-> part 2 include coworker conversation tidbits draft notes:
<ul>
<li>These are two very different languages</li>
<li>These two languages are solving two very different problems</li>
@@ -43,7 +43,7 @@ include coworker conversation tidbits draft notes:
</p>
<p>
- It's not Rust VS Go, it's when to use Rust and when to use Go. And the number
+ It's not Rust vs Go, it's when to use Rust and when to use Go. And the number
one argument I get for why Go should be used is it's simpler and faster to
learn and work with. There's the answer! The answer is use whichever one works
best for you. There's no better or worse, or superiority. Redditors will say
@@ -61,3 +61,44 @@ include coworker conversation tidbits draft notes:
>source</a
>
</p>
+<a
+ href="https://insights.dice.com/2020/08/27/rust-in-trouble-after-big-mozilla-layoffs/"
+ >Is Rust in Trouble After Big Mozilla Layoffs?</a
+>
+<a href="https://foundation.rust-lang.org/posts/2021-02-08-hello-world/"
+ >Hello World! (Rust Foundation)</a
+>
+
+<a href="https://killedbygoogle.com/"> Killed by Google</a>
+
+<p>quotables</p>
+
+<blockquote>
+ Take a look Go as well. I think you will find Go much faster to program in.
+ The other aspect is threading. They have very different threading models. Not
+ sure if you had the chance to research that yet or not
+</blockquote>
+<blockquote>
+ Yes, a big thing is threading. Unfortunately, Rust uses a similar model as
+ Java for threads :(. Go is based on Fibers approach which so much faster for
+ temporary, lightweight requests. Go is definitely superior for HTTP REST API
+ apps. Rust can be better for a single-thread app or general "systems"
+ programming.
+</blockquote>
+<blockquote>
+ The only way is to learn and try both. That's what I did. Most of the info
+ from both sides is biased...Go is definitely very fast and [garbage
+ collection] is not the issue people make it out to be. I started last month
+ porting [a chess] engine to Rust. I recently took a break from it because the
+ syntax and borrow checking were getting insane to deal with. Once I learned
+ about the threading issues in Rust, I have put it on the shelf for now. Rust
+ is still evolving which is good and bad. It needs better IDE and Debugging
+ support than current levels. Hopefully that will continue to improve. There
+ was a big Mozilla shakeup (Nov 2020) where they let go of the Rust developers
+ and cancelled the project. AWS hired them. So honestly, I am not sure which
+ direction the language is going in. Meaning, now that AWS owns the braintrust,
+ I don't know where they are headed. My guess is that AWS is using Rust for
+ some behind the scenes script-like stuff. Not sure. Will be important in the
+ next year or two on which direction things end up going. For Rust to benefit
+ long-term, it needs the support of a corporate backer
+</blockquote>
diff --git a/drafts/make-your-web-site-look-boring.html b/drafts/make-your-web-site-look-boring.html
index c43b218..c8cd03a 100644
--- a/drafts/make-your-web-site-look-boring.html
+++ b/drafts/make-your-web-site-look-boring.html
@@ -1,3 +1,3 @@
<h1>Make Your Web Site Boring!</h1>
-- functional - not disctracting - tasteful - readable
+- functional - not disctracting - tasteful - readable no javascript? no runtime!
diff --git a/drafts/my web site has no runtime.html b/drafts/my web site has no runtime.html
deleted file mode 100644
index 7b60165..0000000
--- a/drafts/my web site has no runtime.html
+++ /dev/null
@@ -1 +0,0 @@
-no javascript? no runtime!
diff --git a/index.html b/index.html
index 299380a..ffbdf28 100644
--- a/index.html
+++ b/index.html
@@ -67,6 +67,7 @@
</h1>
<ul id="index">
+<li> <a href="/posts/unix/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html">How to Automate Certbot Renewal with HAProxy <code>Fri, 19 Mar 2021</code> </a> </li>
<li> <a href="/posts/life/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal-.html">Louis Vierne Is a BAMF (and Proof That Organists Are Metal) <code>Fri, 12 Feb 2021</code> </a> </li>
<li> <a href="/posts/programming/2021-01-28-undefined-javasript-is-undefined-.html">Undefined? JavaSript Is Undefined. <code>Thu, 28 Jan 2021</code> </a> </li>
<li> <a href="/posts/life/2021-01-15-adam-s-2020-reading-list.html">Adam's 2020 Reading List <code>Fri, 15 Jan 2021</code> </a> </li>
diff --git a/info.html b/info.html
index 5842f7d..629e05b 100644
--- a/info.html
+++ b/info.html
@@ -61,23 +61,20 @@
<h2>About Me</h2>
<p>
- My name is <em>Adam Carpenter</em> (on some sites I'm <em>53hornet</em>)
- and this is my personal web site.
+ My name is <em>Adam Carpenter</em> (on some sites I'm
+ <em>53hornet</em>). I am a professional computer programmer, am married
+ to my wonderful wife, Amy, and a puppy parent to Clementine, a Cocker
+ Spaniel. This is my web site.
</p>
+ <p>You can find my <a href="/cv.html">CV here</a>.</p>
+
<p>
<img
src="https://nextcloud.53hor.net/index.php/s/zL2AJHwtCWLX2Eq/preview"
/>
</p>
- <p>
- I am a professional computer programmer. I also see myself as a loving
- husband and doting puppy parent.
- </p>
-
- <p>You can find my <a href="/cv.html">detailed CV here</a>.</p>
-
- <h2>What Will You Find Here?</h2>
+ <h2>What Else Will You Find Here?</h2>
<p>
This site is my home on the web. I post things I've learned, things I
@@ -126,13 +123,8 @@
>here is my GPG public key</a
>.
</span>
- </p>
-
- <p>
- The best way to keep up with what I'm up to is not "social" media. I'm
- terrible at reading it, following it, and posting on it. If I have
- something to share it will go on this site! The best way to keep up with
- this site is to use an RSS reader on <a href="/rss.xml">my feed</a>.
+ The best way to keep up with what I'm up to is to use an RSS reader on
+ <a href="/rss.xml">my feed</a>.
</p>
<p>
@@ -242,7 +234,8 @@
The structure and content of this page are loosely based on
<a href="https://www.worthe-it.co.za/about.html"
>Justin Wernick's about page</a
- >.
+ >. The structure and content of my CV is loosely based on
+ <a href="https://benhoyt.com/cv/">Ben Hoyt's Resume/CV</a>.
</p>
<img
diff --git a/posts/unix/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html b/posts/unix/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html
new file mode 100644
index 0000000..634530b
--- /dev/null
+++ b/posts/unix/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html
@@ -0,0 +1,256 @@
+<!DOCTYPE html>
+<html>
+ <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 src="/includes/icons/home-roof.svg" />
+ Home
+ </a>
+ </li>
+ <li>
+ <a href="/info.html">
+ <img src="/includes/icons/information-variant.svg" />
+ Info
+ </a>
+ </li>
+ <li>
+ <a href="https://git.53hor.net">
+ <img src="/includes/icons/git.svg" />
+ Repos
+ </a>
+ </li>
+ <li>
+ <a href="/hosted.html">
+ <img src="/includes/icons/desktop-tower.svg" />
+ Hosted
+ </a>
+ </li>
+ <li>
+ <a type="application/rss+xml" href="/rss.xml">
+ <img 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>
diff --git a/rss.xml b/rss.xml
index 804f645..6efc861 100644
--- a/rss.xml
+++ b/rss.xml
@@ -140,5 +140,6 @@
<item> <title>Adam's 2020 Reading List</title> <pubDate>Fri, 15 Jan 2021</pubDate> <link>https://www.53hor.net/posts/life/2021-01-15-adam-s-2020-reading-list.html</link> <guid>https://www.53hor.net/posts/life/2021-01-15-adam-s-2020-reading-list.html</guid> </item>
<item> <title>Undefined? JavaSript Is Undefined.</title> <pubDate>Thu, 28 Jan 2021</pubDate> <link>https://www.53hor.net/posts/programming/2021-01-28-undefined-javasript-is-undefined-.html</link> <guid>https://www.53hor.net/posts/programming/2021-01-28-undefined-javasript-is-undefined-.html</guid> </item>
<item> <title>Louis Vierne Is a BAMF (and Proof That Organists Are Metal)</title> <pubDate>Fri, 12 Feb 2021</pubDate> <link>https://www.53hor.net/posts/life/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal-.html</link> <guid>https://www.53hor.net/posts/life/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal-.html</guid> </item>
+<item> <title>How to Automate Certbot Renewal with HAProxy</title> <pubDate>Fri, 19 Mar 2021</pubDate> <link>https://www.53hor.net/posts/unix/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html</link> <guid>https://www.53hor.net/posts/unix/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html</guid> </item>
</channel>
</rss>