How issue a certificate from Let's Encrypt NOT Using HTTPS or HTTP - ACME.SH

Let’s make things easier with ACME.SH

Certbot is the default client to issue a certificate from Let’s Encrypt.
Why not use Certbot?
Certbot requires bind port 80 or 443 but many ISP doesn’t let incoming requests from port 80 or 443.
Certbot also required port forward so you must open the port 80 or 443 to renew certs.

The solution to this is to use a lightweight client - ACME.SH with ACME DNS-01 challenge

  • It does not requires any port forwarding.
  • An ACME protocol client written purely in Shell (Unix shell) language.
  • Full ACME protocol implementation.
  • Bash, dash and sh compatible.
  • Simplest shell script for Let’s Encrypt free certificate client.
  • Purely written in Shell with no dependencies on python or the official Let’s Encrypt client.
  • Just one script to issue, renew and install your certificates automatically.
  • DOES NOT require root/sudoer access.

How It Works

There is some way to get a valid Certificate, one of then is DNS

When the identifier being validated is a domain name, the client can
   prove control of that domain by provisioning a resource record under
   it.  The DNS challenge requires the client to provision a TXT record
   containing a designated value under a specific validation domain
   name.

   type (required, string):  The string "dns-01"

   token (required, string):  A random value that uniquely identifies
      the challenge.  This value MUST have at least 128 bits of entropy,
      in order to prevent an attacker from guessing it.  It MUST NOT
      contain any characters outside the URL-safe Base64 alphabet and
      MUST NOT contain any padding characters ("=").

   {
     "type": "dns-01",
     "token": "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
   }

   A client responds to this challenge by constructing a key
   authorization from the "token" value provided in the challenge and
   the client's account key.  The client then computes the SHA-256
   digest of the key authorization.

   The record provisioned to the DNS is the base64url encoding of this
   digest.  The client constructs the validation domain name by
   prepending the label "_acme-challenge" to the domain name being
   validated, then provisions a TXT record with the digest value under
   that name.  For example, if the domain name being validated is
   "example.com", then the client would provision the following DNS
   record:

   _acme-challenge.example.com. 300 IN TXT "gfj9Xq...Rg85nM"

So ACME.SH use DNS API from providers to generate and send automatically a TXT Record to prove that domain belongs to you.

Step 1: SET UP A DUCKDNS ACCOUNT

Open your browser and go to https://duckdns.org.

Sign in and create an account using one of the id validation options in the top right corner.

In the domains section pick a name for your subdomain, this can be anything you like, and click add domain.

The URL you will be using later to access your Home Assistant instance from outside will be the subdomain you picked, followed by duckdns.org . For our example we will say our URL is examplehome.duckdns.org

https://www.duckdns.org/

STEP 2: Configure AutoUpdate of DNS Domain

https://home-assistant.io/addons/duckdns/
or
https://www.duckdns.org/install.jsp

Step 3: Instal ACME.SH as homeassistant user

$ sudo su - home assistant
$ curl https://get.acme.sh | sh

Output: 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   705  100   705    0     0    499      0  0:00:01  0:00:01 --:--:--   499
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  150k  100  150k    0     0   277k      0 --:--:-- --:--:-- --:--:--  277k

[Fri  1 Sep 13:57:31 -03 2017] Installing from online archive.
[Fri  1 Sep 13:57:31 -03 2017] Downloading https://github.com/Neilpang/acme.sh/archive/master.tar.gz
[Fri  1 Sep 13:57:33 -03 2017] Extracting master.tar.gz
[Fri  1 Sep 13:57:33 -03 2017] Installing to /home/homeassistant/.acme.sh
[Fri  1 Sep 13:57:33 -03 2017] Installed to /home/homeassistant/.acme.sh/acme.sh
[Fri  1 Sep 13:57:33 -03 2017] No profile is found, you will need to go into /home/homeassistant/.acme.sh to use acme.sh
[Fri  1 Sep 13:57:33 -03 2017] Installing cron job
no crontab for homeassistant
no crontab for homeassistant
[Fri  1 Sep 13:57:34 -03 2017] Good, bash is found, so change the shebang to use bash as preferred.
[Fri  1 Sep 13:57:35 -03 2017] OK
[Fri  1 Sep 13:57:35 -03 2017] Install success!

## Check crontab job for auto renew.
$  crontab -l
    33 0 * * * "/home/homeassistant/.acme.sh"/acme.sh --cron --home "/home/homeassistant/.acme.sh" > /dev/null

STEP 4: Just issue a cert using DNS API

Note: Automatic DNS API integration have a huge List of Provider supported - check here https://github.com/Neilpang/acme.sh#9-automatic-dns-api-integration

On this case I’m using DuckDNS API

run as “homeassistant” user

Command to generate certs using DuckDNS

$ sudo su - homeassistant 
$ export DuckDNS_Token="<your token id >"
$ cd ~/.acme.sh/
$ ./acme.sh --insecure --issue --dns dns_duckdns -d <your_sub_domain>.duckdns.org

Example Output:
[Fri  1 Sep 14:00:23 -03 2017] Registering account
[Fri  1 Sep 14:00:29 -03 2017] Registered
[Fri  1 Sep 14:00:30 -03 2017] Update account tos info success.
[Fri  1 Sep 14:00:30 -03 2017] ACCOUNT_THUMBPRINT='[redacted]'
[Fri  1 Sep 14:00:30 -03 2017] Creating domain key
[Fri  1 Sep 14:00:35 -03 2017] The domain key is here: /home/homeassistant/.acme.sh/example.duckdns.org/example.duckdns.org.key
[Fri  1 Sep 14:00:35 -03 2017] Single domain='example.duckdns.org'
[Fri  1 Sep 14:00:35 -03 2017] Getting domain auth token for each domain
[Fri  1 Sep 14:00:35 -03 2017] Getting webroot for domain='example.duckdns.org'
[Fri  1 Sep 14:00:35 -03 2017] Getting new-authz for domain='example.duckdns.org'
[Fri  1 Sep 14:00:36 -03 2017] The new-authz request is ok.
[Fri  1 Sep 14:00:37 -03 2017] Found domain api file: /home/homeassistant/.acme.sh/dnsapi/dns_duckdns.sh
[Fri  1 Sep 14:00:37 -03 2017] Trying to add TXT record
[Fri  1 Sep 14:00:38 -03 2017] TXT record has been successfully added to your DuckDNS domain.
[Fri  1 Sep 14:00:38 -03 2017] Note that all subdomains under this domain uses the same TXT record.
[Fri  1 Sep 14:00:38 -03 2017] Sleep 120 seconds for the txt records to take effect
[Fri  1 Sep 14:02:41 -03 2017] Verifying:example.duckdns.org
[Fri  1 Sep 14:02:47 -03 2017] Success
[Fri  1 Sep 14:02:47 -03 2017] Trying to remove TXT record
[Fri  1 Sep 14:02:48 -03 2017] TXT record has been successfully removed from your DuckDNS domain.
[Fri  1 Sep 14:02:48 -03 2017] Verify finished, start to sign.
[Fri  1 Sep 14:02:50 -03 2017] Cert success.
-----BEGIN CERTIFICATE-----
[redacted]
-----END CERTIFICATE-----
[Fri  1 Sep 14:02:50 -03 2017] Your cert is in  /home/homeassistant/.acme.sh/example.duckdns.org/example.duckdns.org.cer
[Fri  1 Sep 14:02:50 -03 2017] Your cert key is in  /home/homeassistant/.acme.sh/example.duckdns.org/example.duckdns.org.key
[Fri  1 Sep 14:02:51 -03 2017] The intermediate CA cert is in  /home/homeassistant/.acme.sh/example.duckdns.org/ca.cer
[Fri  1 Sep 14:02:51 -03 2017] And the full chain certs is there:  /home/homeassistant/.acme.sh/example.duckdns.org/fullchain.cer

Step 5: ConfigureHA to use Certs

The final step is to point Home Assistant at the generated certificates.

http:
  api_password: YOUR_SECRET_PASSWORD
  ssl_certificate: /home/homeassistant/.acme.sh/example.duckdns.org/fullchain.cer
  ssl_key: /home/homeassistant/.acme.sh/example.duckdns.org/example.duckdns.org.key

Hope it helps.

8 Likes

@leviweb This sounds interesting, I have to dive into it a little more so that I can understand it. So are you saying that this will install the certificate (from a system that does not have a cert already) and it will keep updating it automatically? I am not sure that I understand what the cron job is doing? Also not sure of your installation, if I have the All In One Installer (AIO) should I be logged in to the virtual environment before following these directions? Where do you install it from? the “pi” or “homeassistant” home directory.
Thanks for your contribution.

So are you saying that this will install the certificate (from a system that does not have a cert already) and it will keep updating it automatically?

Yes, It will create a new valid cert from Let’s Encrypt.
Yes, cron job will automatically renew certs when it get expired.

Useful when use the App Home Assistant (android or IOS) that require a ssl/tls with valid certs

I am not sure that I understand what the cron job is doing? Also not sure of your installation, if I have the All In One Installer (AIO) should I be logged in to the virtual environment before following these directions? Where do you install it from? the “pi” or “homeassistant” home directory

Cron Job is for automatic renew certs purpose.
Also have AIO, I logged as “homeassistant”, but you can use any OS user, the homeassistant user must have read permission on certs.

Regards,
Levi Pereira

Thanks Levi,
That may solve my problem. I wanted to have a method that the cert would renew automatically without my intervention and remembering to open up ports etc.

So to be clear, you did the following before installing:
sudo su -s /bin/bash homeassistant
source /srv/homeassistant/homeassistant_venv/bin/activate

Correct?
Thanks again.

Thanks Levi,
That may solve my problem. I wanted to have a method that the cert would renew automatically without my intervention and remembering to open up ports etc.

So to be clear, you did the following before installing:
sudo su -s /bin/bash homeassistant
source /srv/homeassistant/homeassistant_venv/bin/activate

You don’t need activate the virtualenv because ACME.SH configuration doesn’t require it.

Just “sudo su - homeassistant” is enough to make your setup.

But if you activate it will make no diff.

Regards,
Levi

Tried all the steps. Keys generated but after restart HA didn’t start. No error in logs. If i remove ssl conf from configuration.yaml it works fine. Am i missing some step.

Check if cert files has read permission to user homeassistant.

1 Like

They have proper permissions. I even tried changing it to 755. Do we have to fwd the ports also with this.

I had Let’s Encrypt generate certificate, but just changed to Acme, believing it renews the certificate automatically via crontab - correct?
Also, how could I see days left for the certificate to expire via HA UI?
Thank you!

Hello @leviweb !
Got it all set up now using acme instead of certbot, but I would like to make sure that this is going to renew the certificate automatically and when exactly…or do I need to do something else. Sorry for the silly question, if it sounds as such to you!

Cheers,

Yes …If your DNS provider supports API access,you can use that API to automatically issue the certs.
Nothing to do after configured

1 Like

Hell @leviweb,

I now need to add the port to the end of the domain so that it reaches and loads the page. With CertBot, port was not required in the address bar. Could you tell me what I may be missing?

Thanks.

Same here i have to add the 8123 at the end to. Is any way to change that?
Thanks

1 Like

Does anyone else have the same problem, other then me and Antonio, or we did something wrong??? Can someone confirm that.
Other then having to add the port number to the address everything works.
Thanks

Hi,
The certs does not requires configure any port it’s just a cert. The only thing closest to configure port is to renew the cert when using Certboot ( not this case here when use ACME.SH) where it requires incoming port (80, 443) to estabilish connection with let’s encrypt, but nothing to do with HAS Port.
HAS port is defined in the HTTP Session - https://home-assistant.io/components/http/
server_port (Optional): Let you set a port to use. Defaults to 8123.

I can try help you with port, but again is not about issue a cert or acme.sh:
To use default port for https, just set 443 in server_port or if you want access HAS from Wan using https port configure a port fowarding in your router from 443 to HAS Server_port (default is 8123).

Thanks for your response and for the time you invested on this project.

Not having to open a particular port to install or renew the certificates was the reason that i chose to use this way instead of getting certificates through Certboot.
Unfortunately having to open port 443 to stop the hassle of inserting 8123 at the end of my external address (ex https://xxxx.duckdns.org:8123) is not a solution. Especial permanent opening the port 443 that ca have a bad result, from what i understand.
Thanks for your help is much appreciated.
With respect
Adi

Unfortunately having to open port 443 to stop the hassle of inserting 8123 at the end of my external address (ex https://xxxx.duckdns.org:8123) is not a solution.

Ok. Are you bothered to enter the port number 8123 at the end of the FQDN.

Did you already check this:

Especial permanent opening the port 443 that ca have a bad result, from what i understand.

I don’t think so, the only concern is to leave 443 open on WAN wide only to renew certs, this should be avoided
due hack attacks.