Categories
Home Automation

Install acme-sh and secure Home Assistant

This is a followup article for the series on how to install and configure the snap-release of Home Assistant. We will use Google Domains as our domain registrar and a TXT-record in our DNS to verify the ownership.

In this article we will install a snap-package of Acme.sh. This an ACME-shell script that issues and renews certificates from Let’s Encrypt.

This snap-release of Acme.sh is not a full version because there is limitations to what a snap-package can do in a confined environment. It’s therefor not possible to restart services etc outside the environment from the app. An app need to support acme-sh’s plug to use certificates and restart itself on renewals.

This release is configured to renew certificates two times a day.

Install and setup acme-sh

Install acme-sh with the snap package manager:

sudo snap install acme-sh

You now have four executables available

  • acme-sh: Normal mode of acme.sh.
  • acme-sh.dns-manual: Run acme.sh under dns-manual mode.
  • acme-sh.connect: connect a snap-instance with acme and expose certificates to it.
  • acme-sh.pub-key: as the daemon that renews certificates is running as root and the owner of the certificates are your user, you will need to add the public key to your authorized_keys to allow the root to run on your behalf.

Issue a new certificate

The computer of my Home Assistant installation is behind a routers firewall and ports for a standalone server is blocked, and I’ll therefor use the DNS-manual mode. If you have the opportunity to open up ports in your firewall and let it be open at all time, then you could use a standalone server etc and the acme-sh-command.

Run the following command to issue a new certificate:

acme-sh.dns-manual --issue -d my.domain.tld

You will the first time using acme-sh get a note about automatic renewal of your certificates. We will do this in a moment, when we have a valid certificate.

Press any key to continue and an additional note about acme.sh will appear. Familiarize yourself with the content and press any key to continue.

Acme.sh will query Let’s Encrypt and fetch an acme-challenge token that we have to add to our DNS-entries with our registrar. The output should look like this:

joachim@:~/Development/home-assistant-configurator$ acme-sh.dns-manual --issue -d test.domain.tld
[Tue Sep 15 15:58:52 CEST 2020] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Tue Sep 15 15:58:53 CEST 2020] Create account key ok.
[Tue Sep 15 15:58:53 CEST 2020] Registering account: https://acme-v02.api.letsencrypt.org/directory
[Tue Sep 15 15:58:54 CEST 2020] Registered
[Tue Sep 15 15:58:54 CEST 2020] ACCOUNT_THUMBPRINT='TOKEN HERE'
[Tue Sep 15 15:58:54 CEST 2020] Creating domain key
[Tue Sep 15 15:58:55 CEST 2020] The domain key is here: /var/snap/acme-sh/68/user-data/joachim/certs/test.domain.tld/test.domain.tld.key
[Tue Sep 15 15:58:55 CEST 2020] Single domain='test.domain.tld'
[Tue Sep 15 15:58:55 CEST 2020] Getting domain auth token for each domain
[Tue Sep 15 15:58:56 CEST 2020] Getting webroot for domain='test.domain.tld'
[Tue Sep 15 15:58:57 CEST 2020] Add the following TXT record:
[Tue Sep 15 15:58:57 CEST 2020] Domain: '_acme-challenge.test.domain.tld'
[Tue Sep 15 15:58:57 CEST 2020] TXT value: 'THIS IS THE TOKEN'
[Tue Sep 15 15:58:57 CEST 2020] Please be aware that you prepend _acme-challenge. before your domain
[Tue Sep 15 15:58:57 CEST 2020] so the resulting subdomain will be: _acme-challenge.test.domain.tld
[Tue Sep 15 15:58:57 CEST 2020] Please add the TXT records to the domains, and re-run with --renew.
[Tue Sep 15 15:58:57 CEST 2020] Please add '--debug' or '--log' to check more details.
[Tue Sep 15 15:58:57 CEST 2020] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh

You can try to flush the DNS-cache, if you’re in a hurry and want to run the renew command instantly, with the command

sudo systemd-resolve --flush-caches

And then issue the command

acme-sh.dns-manual --renew -d test.domain.tld

It’s however advised to wait about 10 minutes as if the --renew option fails it will force you to re-run the --issue command, and you will have to add a new TXT-record and wait again.

When Acme.sh returns successfully, you should get a response like this:

[Tue Sep 15 16:08:59 CEST 2020] Renew: 'test.domain.tld'
[Tue Sep 15 16:09:00 CEST 2020] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Tue Sep 15 16:09:00 CEST 2020] Single domain='test.domain.tld'
[Tue Sep 15 16:09:00 CEST 2020] Getting domain auth token for each domain
[Tue Sep 15 16:09:00 CEST 2020] Verifying: test.domain.tld
[Tue Sep 15 16:09:05 CEST 2020] Success
[Tue Sep 15 16:09:05 CEST 2020] Verify finished, start to sign.
[Tue Sep 15 16:09:05 CEST 2020] Lets finalize the order.
[Tue Sep 15 16:09:05 CEST 2020] Le_OrderFinalize='https://acme-v02.api.letsencrypt.org/acme/finalize/96721776/5199751331'
[Tue Sep 15 16:09:06 CEST 2020] Downloading cert.
[Tue Sep 15 16:09:06 CEST 2020] Le_LinkCert='https://acme-v02.api.letsencrypt.org/acme/cert/03e508e53fd4c801084f45826067dc0da2dc'
[Tue Sep 15 16:09:07 CEST 2020] Cert success.
-----BEGIN CERTIFICATE-----
[ ...removed content ... ]
-----END CERTIFICATE-----
[Tue Sep 15 16:09:07 CEST 2020] Your cert is in /var/snap/acme-sh/68/user-data/joachim/certs/test.domain.tld/test.domain.tld.cer
[Tue Sep 15 16:09:07 CEST 2020] Your cert key is in /var/snap/acme-sh/68/user-data/joachim/certs/test.domain.tld/test.domain.tld.key
[Tue Sep 15 16:09:07 CEST 2020] The intermediate CA cert is in /var/snap/acme-sh/68/user-data/joachim/certs/test.domain.tld/ca.cer
[Tue Sep 15 16:09:07 CEST 2020] And the full chain certs is there: /var/snap/acme-sh/68/user-data/joachim/certs/test.domain.tld/fullchain.cer

You have now issued a certificate successfully and we can now let the daemon try to renew it twice a day (but only when its due) with the command:

acme-sh.pub-key >> ~/.ssh/authorized_keys \
  && chmod 0600 ~/.ssh/authorized_keys

You will find a log for each time the daemon tries to renew your certificates in ~/.cert-renew, in your home-folder.

Connect Home Assistant and Home Assistant Configurator

We’re now going to connect Home Assistant and the Configurator to acme-sh, so they will be able to use the certificates.

First make sure that both home-assistant-snap and home-assistant-configurator is connected with acme-sh.

snap connections | grep "content\[certs\]"

In my case, only home-assistant-snap auto-connected, and I had to home-assistant-configurator manually.

sudo snap connect acme-sh:certs home-assistant-configurator:certs

I could now verify that both apps was connected successfully.

content[certs] acme-sh:certs home-assistant-configurator:certs manual
content[certs] acme-sh:certs home-assistant-snap:certs -

Now, run the command to start connecting the apps

acme-sh.connect

And choose your certificate and the app you want to connect. A successful output should look like this:

Choose certificate:
1: test.domain.tld
Select a cetificate to expose [1 - 1]: 1

= You choose certificate test.domain.tld

Choose connection for test.domain.tld:
1: home-assistant-snap (uuid: 5fc32b48-f66d-11ea-8bed-1b31217176f3)
2: home-assistant-configurator (uuid: ca89a702-f75f-11ea-a3f3-b7362a622e73)
Choose connection [1 - 2]: 1

= You choose connection home-assistant-snap_5fc32b48-f66d-11ea-8bed-1b31217176f3
Released test.domain.tld for connection home-assistant-snap_5fc32b48-f66d-11ea-8bed-1b31217176f3

Since we’re connecting two apps you’ll have to run acme-sh.connect and connect home-assistant-configurator as well. I’m using the same certificate for both instances (running on the same computer) and if you want separate certificates, then you have to issue a new before connecting the configurator.

Configure Home Assistant

Open up the web UI of Home Assistant in your browser, and go into the configurator.

Create a new folder in the root of the configuration folder, that you name configurations. Go into the folder and create a new file called http.yaml, open it and add the following in that file:

ssl_certificate: !secret ssl_cert
ssl_key: !secret ssl_key
ip_ban_enabled: true
login_attempts_threshold: 5

Save the file and go back into the root of the configuration-directory. Open secrets.yaml and create the two secrets ssl_cert and ssl_key like this:

ssl_cert: /var/snap/home-assistant-snap/current/.ssl/fullchain.pem
ssl_key: /var/snap/home-assistant-snap/current/.ssl/privkey.pem

Save the file file and open up configuration.yaml that is in the same directory, and add the following line to the file:

http: !include configurations/http.yaml
logger:
  default: info

Save the file and go back into the terminal.

We will now have to tell Home Assistant which certificate it should use and to decrypt it before use with the command:

sudo snap set home-assistant-snap domain=test.kgv14.dev

Now monitor the log in the terminal session with

sudo journalctl -xef --unit=snap.home-assistant-*

and run

sudo home-assistant-snap.refresh-certs

to manually recognize the certificate, decrypt it and place it in the .ssl-folder within the configuration-folder. This command will, as long as successful, restart Home Assistant.

You should now be able reach your installation at https://your-domain:8123/, taken into account that you have opened up the port 8132 to the outside world, and forwarded request to the local IP of your Home Assistant installation.

Configure the Configurator

Configuring the Configurator is different, but a lot easier, since you can do it directly from the terminal.

Start to set the domain, as you did for home-assistant-snap:

sudo snap set home-assistant-configurator domain=test.domain.tld

And run the command to force a refresh of certificates:

sudo home-assistant-configurator.refresh-certs

Now configure the configurator to use this, as we did in the previous post on how to configure it:

sudo snap set home-assistant-configurator \ 
    server.ssl.certificate=/var/snap/home-assistant-configurator/current/.ssl/fullchain.pem

sudo snap set home-assistant-configurator \ 
    server.ssl.key=/var/snap/home-assistant-configurator/current/.ssl/privkey.pem

Now restart the server sudo snap restart home-assistant-configurator.server and wait for it to boot up.

You will now see that the configurator is no longer available to you from the web UI of Home Assistant. This is because the url of the panel_iframe we made in the article on integrating them, is pointing to http://ip something and not https://domain.

Edit the configuration.yaml and change this property:

sudo vi /var/snap/home-assistant-snap/current/configuration.yaml

Restart Home Assistant with sudo snap restart home-assistant-snap.hass – and BAM! You’re now secure.

Just a few steps left. You need to update the server.hass.api.url with your domain name, and add the ws-url if needed.

Save a snapshot

Now when the hard part of setting up your Home Assistant installation is over, it’s recommended to take a snapshot of your system.

A snapshot is a copy of the user, system and configuration data stored by snapd (the package manager daemon) for one or more snaps on your system. Snapshots are generated manually with the snap save.

snap save home-assistant-snap \
    home-assistant-configurator \
    acme-sh

And tell snapd to store your backup for a month (720 hours)

snap set system snapshots.automatic.retention=720h

If you ever need to restore a snapshot, run snap saved and find the id of the snapshot you want, and run snap restore ID.

Conclusion

We have now issued a new certificate and secured both Home Assistant and Home Assistant Configurator. The public key of the acme-sh daemon was added to our ssh-keys, so the certificates can renew when they are due.

A snapshot is stored in snapd so we can restore if further configurations breaks, or if we just want to test out different approaches and roll back without going over the whole installation process again.

In an upcoming article we will install HACS, but for those who want to test it already can have a dive into the git repository of home-assistant-hacs.

Feel free to leave a comment. And remember, sharing is caring.

Until next time!

Categories
Server

Install and configure ddclient-snap

This article is written i relation to the previous posts on how to install and configure Home Assistant Snap and Home Assistant Configurator.

The installation process in this article is general and do not required Home Assistant installed to work. If you’re unfamiliar of how snap packages works its recommended to read the previous written posts, as they give you a brief introduction.

In this tutorial we’ll be using Google Domains as the registrar. There are examples for configurations for the most used dynamic DNS providers in ddclients repository at github, that can help you with other providers.

Installation

Install ddclient with the following command:

sudo snap install ddclient-snap

When the installation is complete, open the empty file located at /var/snap/ddclient-snap/current/etc/ddclient/ddclient.conf to start configuring

sudo vi /var/snap/ddclient-snap/current/etc/ddclient/ddclient.conf

If you’re not using Ubuntu Core, then you can swap out vi with your favorite editor, for example nano or gedit,

Configure the DNS provider

This is how I do it for my Google Domain and most DNS providers already offer explanations on how you configure ddclient for their service.

  • Login to the registrar overview of Google Domains.
  • Clikk «manage» behind the domain you want to setup dynamic DNS for.
  • Choose DNS from the menubar on the left and scroll down to «Synthetic records».
  • Create a new Dynamic DNS (select from dropdown) subdomain.
  • Press the arrow button next to the newly created subdomain to expand the details, and choose «view credentials».

Configure ddclient

Go back into the editor as described in the installation process and paste the configuration below into your configuration file. Remember to set the login and password fields, and note the apostrophe surrounding the password, which Google Require.

ssl=yes
use=web, web=checkip.dyndns.com
protocol=googledomains
server=domains.google.com
login=USERNAME
password='PASSWORD'
dynamic.domain.com
verbose=yes

(Or go to ddclient.conf.in to find the configuration for your provider.)

Open up a new terminal-session and monitor the logs before you restart ddclient.

sudo journalctl -xef --unit=snap.ddclient-snap.daemon

and restart ddclient

sudo snap restart ddclient-snap.daemon

If you get a positive response, edit the configurations file and remove verbose=yes from the end. Restart ddclient again to apply the new configuration.

Conclusion

We have now configured ddclient to refresh the DNS entry for our domain.

In the upcoming post we’ll show how you can secure your Home Assistant installation with SSL.

For anyone interested in the source code, want’s more detailed information about the release or needs to file a bug report, head over to the official repository.

If you have any questions, do not hesitate to leave a comment.

Until next time!