How to configure Let's Encrypt SSL Certificates for Home Assistant completely 100% free (Updated for 2022/2023)

You need to begin with dns and certificates 101.

Firstly, .local is not a valid TLD.

Second, because of the first, the only way to get a certificate for such a host name would be to host your own CA, which won’t help you on the wider internet because of the previous point.

For people that are using their own internal certificate authority and want https for INTERNAL USE ONLY. This is not a primer on how to get your certificate authority setup with Acme.sh, just how to get acme.sh installed on your HomeAssistant system and the certificates installed into Nginx Proxy Manager (easiest one for me to use, traefik is complicated). I’m using the Advanced SSH & Web Terminal addon from Frenck to access the server through zhs. I also use Vim as my editor of choice; nano works as well.

Constructive comments are welcome. Again, I’m only using this for the internal network. I access HomeAssistant through a VPN when I want to check on the house remotely.

DNS Records

Make sure host records (A) are stated in the primary DNS zone with necessary reverse records set. I use Technitium DNS as my network DNS server that uses DNS Dynamic Updates through the dns-rfc2136 plugin. This is the dns_nsupdate plugin in acme.sh

Certificate Authority Setup

Copy the certificate authority root and intermediate certificates to /usr/local/share/ca-certificates/root_ca.crt and /usr/local/share/ca-certificates/intermediate_ca.crt, respectfully.

vim /usr/local/share/ca-certificates/root_ca.crt
vim /usr/local/share/ca-certificates/intermediate_ca.crt

update-ca-certificates

Copy your TSIG key into a file within the root directory. I used update as my key name. This key is setup within Technitium DNS to authenticate with the DNS server to enable dynamic DNS zone updates.

vim /root/update.key

Acme.sh Install

Curl is included by default with the Terminal addon but git needs to be installed to clone the acme.sh directory. Set “domain.tld” to whatever your internal domain address is.

apk add git
git clone https://github.com/acmesh-official/acme.sh.git
cd /root/acme.sh
./acme.sh --install -m [email protected]
cd ..
rm -rf /root/acme.sh

Restart the HomeAssistant server.

Acme.sh Account Setup

You need to register the server that is requesting certificates with the certificate authority server but some lines need to be added to the acme.sh configuration file.

vim /root/.acme.sh/account.conf

Add the following lines at the bottom of the file, changing the default values to fit your environment.

SAVED_NSUPDATE_SERVER='dns_server.domain.tld'
SAVED_NSUPDATE_KEY='/root/update.key'
SAVED_NSUPDATE_ZONE='domain.tld'
CA_BUNDLE='/usr/local/share/ca-certificates/root_ca.crt'
USER_PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin'

Acme.sh Account Registration on CA Server

Normally you don’t need bash at the beginning of the following commands, but acme.sh wouldn’t run without bash appended at the front.

bash acme.sh \
--register-account \
--server https://ca_server.domain.tld/acme/acme/directory \
--ca-bundle /usr/local/share/ca-certificates/root_ca.crt \
-m [[email protected]](mailto:[email protected])

Acme.sh Post Hook Script Initialization

touch /usr/local/bin/acme-post.sh
chmod +x /usr/local/bin/acme-post.sh

Acme.sh Certificate Issuance

bash acme.sh --issue --dns dns_nsupdate -d hostname.domain.tld --server https://ca_server.domain.tld/acme/acme/directory --valid-to "+365d" --ca-bundle /usr/local/share/ca-certificates/ --dnssleep 2 --post-hook /usr/local/bin/acme-post.sh

--dns dns_nsupdate specifys the dns-rfc2136 plugin that interacts with the DNS server
--server specifies the location of the certificate authority server on your internal network
--valid-to "+365d" sets the expiration date of the certificate a full year from the issuance date. Default expiration is 60 days.
--dnssleep 2 sets a delay of 2 seconds to allow for dns record propagation on the dns server.
--post-hook calls the post hook script that is initialized above. The script is edited after this command has run once.

To rerun this command to help propagate files called out in the post-hook script, append --force at the end of the certificate issuance command to force a certificate renewal. I usually run the command above 3 times to get the files propagated to the correct places.

Acme.sh Output

The certificate,key, intermeidate CA, and full chain files are stored in: /root/.acme.sh/<hostname>.domain.tld_ecc/<hostname>.domain.tld.cer
/root/.acme.sh/<hostname>.domain.tld_ecc/<hostname>.domain.tld.key
/root/.acme.sh/<hostname>.domain.tld_ecc/ca.cer
/root/.acme.sh/<hostname>.domain.tld_ecc/fullchain.cer

Acme.sh Example Post File

Normally the certificate files don’t need to be moved out of the SSL private store, but in this case the files need to be in the /ssl directory as referenced in the configuration.yaml file.

#!/bin/bash
chmod +w /etc/ssl/private/hostname_cert.*
mv /etc/ssl/private/hostname_cert.pem /etc/ssl/private/hostname_cert.oldpem
mv /etc/ssl/private/hostname_cert.key /etc/ssl/private/hostname_cert.oldkey
cp /root/.acme.sh/hostname.domain.tld_ecc/hostname.domain.tld.cer /etc/ssl/private/hostname_cert.pem
cp /root/.acme.sh/hostname.domain.tld_ecc/hostname.domain.tld.key /etc/ssl/private/hostname_cert.key
mv /ssl/hostname_cert.pem /ssl/hostname_cert.oldpem
mv /ssl/hostname_cert.key /ssl/hostname_cert.oldkey
cp /etc/ssl/private/hostname_cert.pem /ssl/hostname_cert.pem
cp /etc/ssl/private/hostname_cert.key /ssl/hostname_cert.key
chmod 400 /etc/ssl/private/hostname_cert.*

Configuration.yaml

Add the following lines to your configuration.yaml file. I use the Studio Code Server addon to edit the yaml file.

http:
ssl_certificate: /ssl/hostname_cert.pem
ssl_key: /ssl/hostname_cert.key

Nginx Proxy Manager

Copy the contents of the hostname_cert.pem and hostname_cert.key files to discreet files on your desktop to upload to NPM. I use MacOS terminal to copy the contents to .pem and .key files for upload.

cat /ssl/hostname_cert.pem
cat /ssl/hostname_cert.key

Go to “SSL Certificates” witin the NPM interface and choose “Add SSL Certificate” → “Custom” on the right hand side. Type in the name of your server, e.g., “hostname.domain.tld” into the first field. Browse to the location of .key file on your desktop for the second field and the .pem file for the third field. Click “Save” and verify that the expiration date of the certificate is a little more than a year from now.

Click on “Hosts” → “Proxy Hosts” on the top tool bar. Click “Add Proxy Host” on the right hand side. Type the server address in the first field (hostname.domain.tld). There will be a small dropdown below the field that will fill in as you type; click on the dropdown text once you are finished typing to fill in the field. The field will not fill in when you hit enter, you have to click the dropdown text. Change the “Scheme” to “https:”. Type in the full address of the server in the “Forward Hostname/IP” field: https://hostname.domain.tld. Type in the port number: 8123.

Click on the “SSL” tab in this edit window and choose the hostname.domain.tld file from the dropdown menu. Toggle the “Force SSL” option and click “Save.”

You should be able to navigate to your hostname address now with https://hostname.domain.tld:8123 in your browser with a valid SSL certificate.

Edit: If anyone notices issues in this post, comment so I can update the post with correct information.

1 Like