Automate Let's Encrypt Certificate Renewals

This guide (with commentary) is meant to provide one way to manually configure automatic renewal (with a later automatic HA restart, as necessary) of your Let’s Encrypt certificate via the HAOS GUI after initial configuration has been completed. This guide is fairly complicated and may seem daunting, but completing it could teach you multiple new functions that could also be useful in other automations. Parts of this guide are based on my memory, because I did not document things early in the process and wanted to test before publishing. I will also include some commentary on things that won’t work for educational purposes. It should be noted that you can also simply schedule an automation to start the Let’s Encrypt service daily and renewal will occur automatically once the due date is near enough (an automatic HA restart wouldn’t occur in that case). In preparing this guide, it has also come to my attention that a blueprint is available should you prefer to import one of those instead of setting up your own system manually. I have not used the blueprint, but based on a quick glance, it looks like it would provide sliders and toggles to configure renewal to your preferences. However, the blueprint appears to be designed for HASSIO, so I’m not sure if it would even install or function properly in HAOS.

Tracking Cert Expiry

In order to schedule renewal, you need to know when expiration will occur. The Certificate Expiry integration is a great tool to help you meet that requirement. If I remember correctly, the steps to use it are intuitive, simply add it from the Integrations section and follow the on-screen prompts to select your LE cert in order to create a sensor showing when said cert will expire. I didn’t take notes on this process, so if you want more detail, see the Manual configuration steps section of the integration page linked earlier in this paragraph.

In order to complete this guide, you will need the entity ID for the sensor you just created. It will likely be something like sensor.cert_expiry_timestamp_yourdomain_tld_8123 and you can find it from the Integrations section by clicking/tapping 1 entity and then clicking/tapping the entity that is displayed to bring up a window showing the full ID. Save this ID for later.

Automating Renewal

Automations can trigger based on a timestamp, but it is advisable to renew before expiry. In fact, Let’s Encrypt recommends renewing when one third of the cert’s lifetime remains. Certs currently last 90 days, so renewing with 30 days remaining follows this recommendation. I chose to use a datetime helper to achieve this, as that seemed most efficient vs other methods (that are arguably efficient enough). Here are the steps:

  1. Navigate: SettingsDevices & ServicesHelpers

  2. Click/tap + CREATE HELPER

  3. Choose Date and/or time

  4. Provide a name such as “Next Cert Renewal”

  5. Optionally, choose an icon such as “mdi:certificate”

  6. Choose the “Date and time” option under “What do you want to input?”

  7. Click/tap Create

Helpers don’t maintain their values after power failures or full system reboots (vs HA restarts), and these values also need updated after renewals anyway, so I used automations to maintain these values. I originally configured the automations to trigger at HomeAssistant start, and this worked whenever a full system reboot occurred, but I noticed in final testing that the values weren’t updating after HA restarts because the sensor wasn’t available when the automations ran. As such, I changed the automations to run with a state trigger that, based on entity history in my HAOS instance, should theoretically only trigger on reboot. That having been said, here are the steps to create the automation for populating the helper created above:

  1. Navigate: SettingsAutomations & Scenes

  2. Click/tap + CREATE AUTOMATION

  3. Click/tap Start with an empty automation

  4. Click/tap + ADD TRIGGER

  5. Click/tap State

  6. Choose the sensor you created to track cert expiry as the entity

  7. Choose “Unavailable” in the “From (optional)” dropdown so this automation will only trigger when the state of the sensor changes from unavailable (this happen shortly after each HA restart)

  8. Click/tap + ADD ACTION

  9. Click/tap Call Service

  10. Find and choose “Input datetime: Set”

  11. Click/tap + Choose Entity

  12. Select the helper you created in steps 2-7

  13. Click/tap the three dots in the top right corner and switch to “Edit in YAML”

  14. Replace data: {} with data_template:

  15. Remove target:

  16. Now you need to refer to the ID that I told you to save for later when adding the Cert Expiry integration. Replace sensor.cert_expiry_timestamp_yourdomain_tld_8123 with that ID to add a new indented line at the bottom like timestamp: "{{as_timestamp(states('sensor.cert_expiry_timestamp_yourdomain_tld_8123'))-(30*24*60*60)}}"

This last line sets your helper to 30 days before expiration by subtracting 30 days worth of seconds from the expiration time using multiplication to calculate the seconds as 30(days)*24(hours/day)*60(minutes/hour)*60(seconds/minute). You could also replace -(30*24*60*60) with -2592000 to increase efficiency further. You should now have YAML that looks like this for your “Input datetime: Set” action:

service: input_datetime.set_datetime
data_template:
  entity_id: input_datetime.next_cert_renewal
  timestamp: "{{as_timestamp(states('sensor.cert_expiry_timestamp_yourdomain_tld_8123'))-(30*24*60*60)}}"

It will look different if you come back later after saving, but that is OK.

  1. Click/tap SAVE

  2. Provide a name for your automation such as “Schedule cert renewal”

Now we have the time when we want to renew, but we still need to automate renewal. Here are the steps necessary to do that:

  1. Repeat steps 8-11

  2. Click/tap Time

  3. Choose “Value of a date/time helper” for the “Mode”

  4. Select the helper you created in steps 2-7

  5. Repeat steps 15-16

  6. Find and choose Home Assistant Supervisor: Start add-on"

  7. Choose the “Let’s Encrypt” add-on in the “Add-on” dropdown.

  8. Click/tap SAVE

  9. Provide a name for your automation such as “Let’s Encrypt Cert Renewal”

Congratulations, your cert should now automatically renew 30 days before it expires. However, when it renews, your HA instance will still be using the old cert until it is restarted. Given 30 days, there is probably a good chance your instance will be restarted for one reason or another before the cert expires anyway, but if you believe having an expired cert would cause you more grief than having an automated restart, you can schedule a restart to occur when the cert expires.

Automating HA Restart

This optional step is very similar to the steps just performed, and because the helpers will be reset each time HA restarts, this automation will only ever be triggered if your HA instance is still up and running when a previously renewed cert expires. When I was designing this solution for my HAOS instance, I was under the impression that the sensor created with the Certificate Expiry integration would update when the certificate renewed, but that doesn’t appear to be the case. As such, it may be possible to use the actual sensor from the Certificate Expiry integration to trigger an automation at expiration, which would negate negate the need for an additional helper and reduce the number of additional automations to 1, but I wasn’t able to quickly find a way to do that while compiling this guide, so I am using another datetime helper here. Even if the sensor could be used, a helper might be more efficient (since the sensor would presumably involve HA processing a template far more frequently than the sensor is set via automation, even as processing that template would arguably be efficient enough). Since the process for scheduling the restart is nearly identical under these circumstances, I am only providing the steps that are different. You can refer to the previous set of steps for each number that isn’t listed here:

  1. Provide a name such as “Active Cert Expiration”

  2. Now you need to refer to the ID that I told you to save for later when adding the Cert Expiry integration. Replace sensor.cert_expiry_timestamp_yourdomain_tld_8123 with that ID to add a new indented line at the bottom like timestamp: "{{as_timestamp(states('sensor.cert_expiry_timestamp_yourdomain_tld_8123'))}}"

This last line sets your helper to match the sensor. You should now have YAML that looks like this for your “Input datetime: Set” action:

service: input_datetime.set_datetime
data_template:
  entity_id: input_datetime.next_cert_renewal
  timestamp: "{{as_timestamp(states('sensor.cert_expiry_timestamp_yourdomain_tld_8123'))}}"
  1. Provide a name for your automation such as “Record Active Cert Expiration”

Now we have the time when we want to renew, but we still need to automate renewal. Here are the steps necessary to do that:

  1. Find and choose “Home Assistant Core Integration: Restart”

  2. Click/tap SAVE

  3. Provide a name for your automation such as “Reload @ Active Cert Expiry”

Congratulations, your HA instance will now restart when the cert in memory expires. In the future, it may not be necessary to restart HA, as the only component that really needs restarted is the web server, but when I started working on this, there wasn’t an obvious way to restart the web server, and restarting HA was effective, so that’s what I’ve chosen to do. Also note that there is currently no “error handling” here. I didn’t bother with “error handling” because Let’s Encrypt will automatically e-mail me when my cert hasn’t been renewed (I gave it a real e-mail address and didn’t test my automations until after the e-mail came through). However, if you are concerned that you might not get such a notification, the simpler option of running the Let’s Encrypt service once a day may be a better choice for ensuring renewal does occur in the unlikely event that your HA system or Internet connection is down or the Let’s Encrypt system is malfunctioning at the time of the scheduled renewal. Even then, you could still use these same steps to schedule a restart at expiration if you wanted to. On the other hand, if you’ve made it this far and understand what you’ve achieved, you may well be able to mitigate that on your own in a number of ways. For instance, here are two theoretical options:

  • Add a trigger to the renewal automation against the sensor changing from unavailable and add a condition that the helper must match the current time or be in the past. This would make sure that the cert renews if HA was down when the target time passed, but it wouldn’t handle a situation where renewal failed (Internet down, Let’s Encrypt malfunction).

  • Add a notification automation that triggers a number of days before the old cert expires to give yourself time to manually reboot and verify renewal occurred.

  • Adjust the reboot schedule automation to trigger ahead of expiry so that it can work in tandem with the options above to trigger renewal again and/or allow you to check based on a notification.

I’m sure there are plenty of other possibilities, and each one of them can potentially help in other actual home automation tasks, so I’d recommend figuring out what’s right for you.

9 Likes

The Let’s Encrypt addon detects when the cert does not require renewal and exits success with no changes. It did not seem necessary to re-implement that logic with the expiry sensor, so I just schedule the addon to run weekly at an unobtrusive time.

I appreciate learning about the expiry sensor and find it handy to keep installed for the occasional use, even if nothing reads it automatically.

alias: Refresh Let's Encrypt Certificate
description: >-
  Start the LE addon, let it renew the certificate if necessary, wait 15
  minutes, restart HA
trigger: []
condition:
  - condition: time
    after: "03:00:00"
    weekday:
      - sat
    before: "03:00:00"
action:
  - service: hassio.addon_restart
    data:
      addon: core_letsencrypt
  - delay:
      hours: 0
      minutes: 15
      seconds: 0
      milliseconds: 0
  - service: homeassistant.restart
    data: {}
mode: single
4 Likes

I buried that information in the first paragraph when I said:

It should be noted that you can also simply schedule an automation to start the Let’s Encrypt service daily and renewal will occur automatically once the due date is near enough (an automatic HA restart wouldn’t occur in that case).

However, thank you for bringing it to the forefront and providing the simple weekly example. Your particular example would also restart your HA instance once a week, though, correct? That’s probably fine for most users, but worth pointing out. Outside of some flukey scenario where the addon somehow ends up hanging in a running state (which should never happen in your example since you restart after you run it), is there any benefit to using addon_restart vs addon_start? I believe I read some guidance suggesting the restart option, but I used the former intentionally since the addon shouldn’t be in the running state to begin with.

Agreed, it’s definitely a tradeoff. I cleared the scheduled 3 AM restart with stakeholders.

I can’t recall any specific reason I chose “restart” over “start”, it seems functionally identical in my scenario.

I actually don’t mind at all having the restart happen more frequently, because if HA does hang or do something weird, I’d rather find out in 7 days than in 60 – and it’s deliberately early on Saturday morning so I have a convenient time to fix if required.

What does a homeassistant.restart entail? Does it reboot the whole server? or…?

Can we reduce it to a homeassistant.reload_all?

Restart is not quite a reboot, but it is more than a reload. It is what has been reported to work in order to get the web service (not a YAML controlled integration) to load the new certificate. There may be a better way, but it hasn’t come to my attention.

ETA: In case it helps clarify, a reboot would restart the entire kernel (and might even cycle power internally), which takes longer than a restart. A restart takes longer than a reload and technically involves downtime, but it only restarts everything HomeAssistant related. It is somewhat similar to restarting a service that has other dependent services which all must stop before the restart and then start again after.

Ok, .restart it is then. Thank you!

Not only did I need to homeassistant.restart (which took longer than necessary to refresh a cert), I also had to separately restart my VaultWarden add-on which relies on the same certs.

For quite a while, traffic between my SSL reverse proxy and HA/VW was not encrypted, I was hoping to find a good solution to it.

Cert installation/renewal should be more seamless and integrated into HA, otherwise I wonder how the other folks are managing it.

Wanted to share that I think a similar script posted at this link is more succint and readable

Thanks for sharing, the main reason I posted this how to was to familiarize people with the config as opposed to providing a simple script. I’m actually working on another way to do this because I still see room for “improvement” via use of newer features (while there are obviously also simpler ways, I am optimizing becuause I can, not because it is needed).

Just wanted to add to this. I’m running the NGINX reverse proxy addon which stops the Lets Encrypt from auto-renewing since NGINX is running on port 80.

The work around is to stop the NGINX addon, run Let’s Encrypt to get the new cert, then restart NGINX. Script below:

alias: Let's Encrypt Cert Renewal
description: ""
trigger:
  - platform: time
    at: input_datetime.next_cert_renewal
condition: []
action:
  - service: hassio.addon_stop
    data:
      addon: core_nginx_proxy
  - service: hassio.addon_start
    data:
      addon: core_letsencrypt
  - delay:
      hours: 0
      minutes: 2
      seconds: 0
      milliseconds: 0
  - service: hassio.addon_start
    data:
      addon: core_nginx_proxy
mode: single

Thank you for sharing this. I didn’t include instructions for Let’s Encrypt because it is so flexible. For instance, I am using an API to update DNS to confirm my certificates, so I don’t even open port 80 at all.

Separately, I am now doing renewal using the Local Calendar integration, and this has allowed me to ditch the helpers. The only caveat is that I can’t automate deletion of calendar events, so I have an automation reminding me to delete them manually. I have put in a feature request to allow for automation of event deletion if anyone is interested in voting on it.

I followed this guide then realised that you need the Lets Encrypt addon for it to work. Good if this was flagged as a dependency haha

I run HA in a docker container so no addons for me. I have another docker container that generates and renews my SSL certificate so I need to automate a copy/paste of the new certificate,

Anyone know if this is possible in HA?

Just a quick update that I have made some good progress using letsencrypt docker (not the addon) and HA (also a docker container) where my ssl certificate is automatically renewed and then the new certificate is used by HA all without a restart of HA (I hope).

Used Let’s Encrypt for Duck DNS ( maksimstojkovic/letsencrypt) - a docker container that handles the ssl certificate creation and renewal.

Then with my HA docker/compose file, I added a volume/path that mounts to where lets encrypt stores the certificate so it is accessible from within the HA config directory.

Then I just pointed my HA configuration.yaml for ssl certificate to the correct location.

I think with this setup, the certificate will magically get updated on renewal. Might have to restart or get HA to do a certificate renewal but will wait and see what happens automagically!.

Unfortunately, there is no addon tag for me to use on the OP, however, step one of the initial configuration I linked to is just under a header entitled “Get a SSL certificate with Let’s Encrypt Addon,” so I’m not sure where it would be better to indicate the requirement.

In any case, I’m glad you were able to get something working with your containers. That having been said, considering that the Let’s Encrypt add-on replaces the certificate file, and HA continues to serve up the old one; it seems likely to me that the containerized HA instance will also serve its certificate from memory until restarted. I’d recommend setting up a reminder to check and see which certificate is being served via a web browser after the certificate update is complete and before any other restarts so you can know for sure ahead of any expired certificate warning (and plan accordingly if necessary).

Thanks. I missed that. Silly me.

Also read all the comments and see that I will need to restart HA for the new certificate to become active.

I also have setup the input date helper / reminder as per your instructions. So I just need to trigger a notification when the reminder date is reached.

It would be nice if the cert expiry sensor would update without restarting HA. I expect the cert file to automatically update but I doubt the sensor picks this up. If it did update, that would be a good trigger for HA restart.

Thanks again for the guide and help.

Can anyone TL;DR this thread? Is there a way to make LetsEncrypt auto-restart the necessary HA components when necessary?

I’m using the dns-cloudflare provider, and HA OS 10.5. Currently, if I don’t manually restart my HA instance every few months, the cert expires and locks me out.

edit: I think this page Home Assistant: Auto-renewing Let's Encrypt SSL might be the answer. Trying now…

1 Like

Yes, it looks like that should work for you. The toggle to restart home assistant automtically should be what you’re looking for, but it appears to be overkill. They are calling service hassio.host_reboot even though restarting home assistant should be sufficient. Note that steps to achieve a home assstant restart are described under the Automating HA Restart header in my OP, but re: tldr you could change the aforementioned service to homeassistant.restart if you are using the blueprint.

If you get locked out of your Home Assistant instance because of expired certificate, try running the following script as root:

#!/bin/bash

is_user_root () { [ "${EUID:-$(id -u)}" -eq 0 ]; }

if is_user_root; then
    echo "Certbot renew..."
    certbot renew

    echo "Refreshing updates..."
    ha refresh-updates
    
    echo "Updating Letsencrypt addon..."
    ha addons update core_letsencrypt
    
    echo "Restarting Letsencrypt addon..."
    ha addons restart core_letsencrypt
    
    echo "Updating DuckDNS addon..."
    ha addons update core_duckdns
    
    echo "Restarting DuckDNS addon..."
    ha addons restart core_duckdns
    
    echo "Restarting core (be patient)..."
    ha core restart
    
    echo "Done!"
else
    echo "Must be executed by priviledged account!" >&2
    exit 1
fi

Then once you’re back in, try to solve the automatic renewal issue.

To which scenarios would this be specific? For instance, I can log into my HAOS web interface while it is using an expired certificate, so I’m not sure why I’d need this (or if it would work with HAOS, perhaps it is specific to a different install type or perhaps the expired certificate prevents the web interface from loading after a reboot). Steps would also obviously be different for users that do something other than DuckDNS, but those users can likely figure that out.