Let's Encrypt on OctoPi

I could have sworn I'd followed a guide when I set up my last OctoPi system about a year ago, but I just set up another one and couldn't find it. So, not finding one, I decided to write one.

Prerequisites

  • You must own a real, live Internet domain.

As noted in this issue, Let's Encrypt won't issue a cert for a local domain (i.e., something like octopi.local or ender.lan) or for an IP address, so you need a real domain. You can get a domain for free from freenom.com, though they have some annoying renewal requirements and only have certain TLDs available for free. Or you can just pay for a domain; they're generally less than $15/year (and often less than $10/year).

  • You must have a suitable DNS host

This guide is going to use DNS validation to obtain your Let's Encrypt certificate, so nothing on your LAN needs to be exposed to the Internet. For this to work, you'll need to be using a DNS host with an API that's supported by acme.sh. I like, use, and recommend Cloudflare, and will use that in the examples here, but as you can see in the link in the last sentence, acme.sh supports over 50 DNS hosts. Cloudflare provides DNS service for free, so unless you have a particular reason to prefer a different host, I'd recommend using them.

  • Your router, or whatever is serving DNS for your LAN, needs to be configured properly

You're going to be getting a certificate for a specific hostname (I'll use octopi.yourdomain.com in these examples). For this to work without certificate errors, that hostname will need to resolve to your OctoPi instance on your local network (i.e., https://octopi.yourdomain.com will actually point to your OctoPi system).

Installing acme.sh

Many guides for using Let's Encrypt have you use the certbot client. I don't like using that if I can avoid it, though, as it's a tangled mess of dependencies that is far too bloated for most purposes. Instead, this guide uses acme.sh, a lightweight ACME client in a shell script. Installation is simple.

Log in to your OctoPi instance as the default pi user, then become root by running sudo -i. Then, to install acme.sh, run curl https://get.acme.sh | sh. This will download acme.sh, put it in /root/.acme.sh/, and configure a daily cron job to renew your certificates. Log out of this root session by typing exit or Ctrl-D, then run sudo -i again--this will activate the new PATH acme.sh configured.

Issue the certificate

It's now time to issue the certificate. To do this, you'll need to have access to the appropriate API credentials for your DNS host--for Cloudflare, that's the Global API key and the email address on your account. Then set the appropriate environment variables:

export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
export CF_Email="xxxx@sss.com"

If you're using a different DNS host, consult the acme.sh documentation (at the "supported by acme.sh" link above) for the appropriate credentials and how to set them. Once you've done that, issue the certificate. Run the command below, replacing every instance (there are four) of octopi.yourdomain.com with the FQDN you're going to use for your OctoPi system:

acme.sh --issue --dns dns_cf -d octopi.yourdomain.com --renew-hook "cat /root/.acme.sh/octopi.yourdomain.com/fullchain.cer /root/.acme.sh/octopi.yourdomain.com/octopi.yourdomain.com.key >/etc/ssl/snakeoil.pem && systemctl reload haproxy"

If all goes well, this will issue your cert.

The --renew-hook parameter tells acme.sh which command(s) to run to deploy a cert after it's renewed, but they don't run when the cert is first issued. So, after issuing the cert, you'll need to run these manually. As above, you'll need to replace every instance (there are three this time) of octopi.yourdomain.com with the FQDN you're going to use for your OctoPi system:

cat /root/.acme.sh/octopi.yourdomain.com/fullchain.cer /root/.acme.sh/octopi.yourdomain.com/octopi.yourdomain.com.key >/etc/ssl/snakeoil.pem
systemctl reload haproxy

That's it! You have your trusted certificate installed and activated, and it will automatically renew every 60 days or so. And you haven't needed to change any of the default configuration files to do so.

HTTPS redirect

You have your certificate issued and installed, but HTTP requests aren't redirected to HTTPS. You can set this up by adding these two lines to /etc/haproxy/haproxy.cfg:

#redirect to HTTPS if ssl_fc is false / off, unless using the API.
redirect scheme https code 301 if !{ url_beg /api } !{ ssl_fc }

These are added to the frontend section, so it will look like this:

frontend public
        bind :::80 v4v6
        bind :::443 v4v6 ssl crt /etc/ssl/snakeoil.pem
        option forwardfor except 127.0.0.1
        #redirect to HTTPS if ssl_fc is false / off, unless using the API.
        redirect scheme https code 301 if !{ url_beg /api } !{ ssl_fc }
        use_backend webcam if { path_beg /webcam/ }
        default_backend octoprint

Then reload haproxy with systemctl reload haproxy, and the redirect will be in place. To test it, browse to http://octopi.yourdomain.com, and note that you're automatically redirected to HTTPS.

5 Likes

old thread... but this might help out... at least it did for me.

I generated my letsencrypt certs for my domain on a different server. I copy me /etc/letsencrypt dir to my servers after the certs are created or renewed. On my octopi, I added
lua-load /root/bin/update_haproxy_ssl_certs.lua
to the global section in the haproxy.cfg file.
I made lua-load /root/bin/update_haproxy_ssl_certs.lua do:
#!/usr/bin/lua
os.execute ('/root/bin/update_haproxy_ssl_certs.sh')
and /root/bin/update_haproxy_ssl_certs.sh do
#!/bin/bash
LETSENCRYPT=/etc/letsencrypt/live/mydomain.net/
if [[ $LETSENCRYPT/fullchain.pem -nt /etc/ssl/snakeoil.pem ]]; then
cat $LETSENCRYPT/fullchain.pem $LETSENCRYPT/privkey.pem > /etc/ssl/snakeoil.pem
fi

so that when I refresh the /etc/letsencrypt dir with updates I can just reload haproxy and not have to worry about updating the snakeoil cert.

1 Like

Why put the shiny new valid certificate into snakeoil.pem? As the name suggests this is expected to be an invalid dummy. I'd rather put it into /etc/haproxy/ssl/mydomain.pem and edit haproxy's config to point to that place.

I use dehydrated and the free name servers at dns.he.net and and there's a hook script to create and renew the certs

Because that's what's already configured in the file, the name doesn't really mean anything, and this way there are minimal edits. You can, of course, call the file whatever you like and edit haproxy.cfg to match.

the name doesn't really mean anything

except telling everyone with a loud voice that the content of this cert is not valid. Language is supposed to transport information.

1 Like

Well, "everyone" who happens to look at haproxy.cfg but has no idea what they've done in the past. I expect that to be a vanishingly small group. But hey, it's your system, do what you like with it. And if you think a filename of snakeoil.pem must necessarily mean that its contents are "an invalid dummy", then by all means change it to something else.

As I said, for purposes of the guide, I used that filename to minimize the edits to haproxy.cfg. The less people have to edit, the less the chance of editing incorrectly.

1 Like