Certificate Authority and self-signed certificate for SSL/TLS

:warning: This guide has been migrated from our website and might be outdated. Feel free to edit this guide to update it, and to remove this message after that.

If your Home Assistant instance is only accessible from your local network, you can still protect the communication between your browsers and the frontend with SSL/TLS.

Let’s Encrypt will only work if you have a DNS entry and remote access is allowed.

The solution is to use a self-signed certificate. Please note, however, that after you have completed these steps, your browser will complain about the security of the certificate as it was not issued by a trusted authority.

  • This is due to self-signed certificates having not been issued by a certification authority (CA). If you have your own CA, then this will not be an issue.

  • A fantastic workaround for this, while keeping your instance isolated securely off the Internet, is to use a Certificate for SSL/TLS via domain ownership.

If you don’t mind the browser warnings and simply want SSL/TLS encryption and therefore have decided to use a self-signed certificate permanently or temporarily, read on!

If you use Chrome browser version 58 or above and/or don’t want to have issues regarding a non-trusted CA or CN (Common Name), follow this full tutorial: Create Root Certificate Authority and self-signed certificate for your Home Assistant. Compatible with Chrome browser > version 58. Otherwise, follow this:

To create a certificate locally, you need the OpenSSL command-line tool.

Change to your Home Assistant configuration directory like ~/.homeassistant. This will make it easier to backup your certificate and the key. Run the command shown below.

The certificate must be .pem extension.

openssl req -sha256 -addext "subjectAltName = IP:X.X.X.X" -newkey rsa:4096 -nodes -keyout privkey.pem -x509 -days 730 -out fullchain.pem

Where the X.X.X.X must be replaced with the IP address of your local machine running Home Assistant (e.g., 192.168.1.20).

For details about the parameters, please check the OpenSSL documentation. Provide the requested information during the generation process.

At the end you will have two files called privkey.pem and fullchain.pem. The key and the certificate.

Update the http: entry in your configuration.yaml file and let it point to your created files.

Home Assistant & Home Assistant Supervised:

http:
  ssl_certificate: /ssl/fullchain.pem
  ssl_key: /ssl/privkey.pem

Home Assistant Core:

http:
  ssl_certificate: /home/your_user/.homeassistant/fullchain.pem
  ssl_key: /home/your_user/.homeassistant/privkey.pem

Home Assistant Core on Docker:

http:
  ssl_certificate: /config/fullchain.pem
  ssl_key: /config/privkey.pem

A restart of Home Assistant is required for the new certificate to take effect.

If you get any log error about ssl_key or ssl_certificate that is not a file for dictionary value when run Home Assistant, you need to change owner or access permission of the .pem files as following:

Home Assistant (through console or SSH add-on):

chown root:root fullchain.pem privkey.pem
chmod 600 fullchain.pem privkey.pem

Home Assistant Core:

sudo chown homeassistant:homeassistant fullchain.pem privkey.pem
sudo chmod 600 fullchain.pem privkey.pem

A tutorial “Working with SSL Certificates, Private Keys and CSRs” could give you some insight about special cases.

iOS and macOS Specific Requirements

iOS

If you are going to use this certificate with the iOS app, you need to ensure you complete all fields during the certificate creation process, then:

  • Send only the fullchain.pem file to the iOS device, using airdrop or other transfer method.
  • Open the .pem file on the iOS device, follow the prompts to trust and install it.
  • If you are using iOS 10.3 or newer then additional steps are needed.

iOS 13 and macOS 10.15

There are new security requirements for TLS server certificates in iOS 13 and macOS 10.15. To summarize:

  • The key size must be greater than or equal to 2048 bits.
  • A hash algorithm from the SHA-2 family is required. SHA-1 signed certificates are no longer trusted for TLS.
  • The DNS name of the server must be included in the Subject Alternative Name extension of the certificate.
  • For certificates issued after July 1, 2019:
    • Certificates must contain an ExtendedKeyUsage (EKU) extension containing the id-kp-serverAuth OID.
    • Certificates must have a validity period of 825 days or fewer.
2 Likes

The validity period of the root certificate can still be ‘unlimited’, e.g. 7300 days. The validity period of 825 days is for server certificates, e.g. the Home Assistent server.

Hi everyone,

thanks for the instructions although I maybe have some improvements.

In my case, I had to change the parameters for creating the ssl certificate.
The command in the Instruction uses -addext "subjectAltName = IP:X.X.X.X" to add the IP-Adress of the client running Home Assistant to the certificate.

But, since Apple changed the requirements for trusted certifictates, you will have to change this to the DNS-Name of your Home-Asssistant- Client like this: -addext "subjectAltName = DNS:<your-dns-name>". That’s why I couldn’t install the certificate on my iPad running iPadOS 14. Although for some reason the installation on my Galaxy S9 with Android 10 also failed. Changing the parameters fixed both issues! :smiley:

Only after doing this, I was able to install the certificate on my Android- and IOS-Devices. :slight_smile:

Maybe it helps someone. :upside_down_face:

Greets,
LineC0der

What needs to be done to get SSL working with the HA app on Android with a pure internal SSL connection?

You need a to import the certificate into the certificate store on android. I got it running with the help of the links in this comment:

Now, is there anyway to allow unencrypted calls too? Like in a normal server (80 and 443 both allowed).

The reason be, that I expect that this selfsigned certificate can become an issue from time to time.

Summary and instructions for private certificate as per my experience. Most input is from this thread.

Home assistant private certificate instructions

  1. Pre-requisites
  • install NGINX Home Assistant SSL proxy add-on, do not start it yet
  • install Terminal & SSH add-on (because you need to copy the certificates to home assistant)
  • install File editor add-on
  1. Create certificate in any linux machine, domain name in the command below must be correct.

openssl req -sha256 -addext "subjectAltName = DNS:myhost.domainname.com" -newkey rsa:4096 -nodes -keyout privkey.pem -x509 -days 730 -out fullchain.pem

Copy fullchain.pem and privkey.pem files to HA /root/ssl. Alternatively you can also copy the file content and create new file using vi editor.
Make sure they look like below.

[core-ssh ssl]$ pwd
/root/ssl
[core-ssh ssl]$ ls -l *.pem
-rw-r--r--    1 root     root          1980 Oct 15 16:39 fullchain.pem
-rw-------    1 root     root          3272 Oct 15 16:39 privkey.pem
[core-ssh ssl]$
  1. Set NGINX Home Assistant SSL proxy and start the add-on.

NGINX Home Assistant SSL proxy configuration, note the domain name must match with the certificate and must be the one you are coming in to the home assistant.

domain: myhost.domainname.com
certfile: fullchain.pem
keyfile: privkey.pem
hsts: max-age=31536000; includeSubDomains
cloudflare: false
customize:
  active: false
  default: nginx_proxy_default*.conf
  servers: nginx_proxy/*.conf
  1. Set NGINX Home Assistant SSL proxy Start on boot to YES once confirmed working.

  2. Conect to myhost.domainname.com(:optional port number) using Firefox, accept risk and continue.

Go to Firefox settings,

  • Find: view certificates
  • Click View Certificates - Servers

Select your Certificate and Export certificate, type DER. After export rename file extension to be .cer

  1. Copy certificate file to Android phone Download folder.

In Android settings, search for CA Certificate. Install certificate from Internal storage Download folder.

  1. Edit Home assistant configuration.yaml

Add trusted proxy, this network IP address may vary but you should see the value in log.

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 172.30.33.0/24
  1. Go to Home assistant Android application and set home assistant URL to

https://myhost.domainname.com(:optional port number)

Remote connection should work now in certification point of view.

1 Like

For those of you that want a certificate for a server with multiple names you could use this command:
openssl req -sha256 -addext "subjectAltName = DNS.1:homeassistant.domain1.com, DNS.2: homeassistant.domain2.com, DNS.3: homeassistant.domain3.com" -newkey rsa:4096 -nodes -keyout HomeAssistant.borgcube.com.key -x509 -days 730 -out HomeAssistant.borgcube.com.pem

Easiest solution, throw the iPhone into the sea and buy something else. It’s a freaking nightmare!

2 Likes

I was able to create a cert for local access SSL via mkcert only to finally discover this would work with iPhone, Mac and Windows but not with the HA Companion app which insisted on declining the self signed cert :frowning:

I was stuck on this for 2/3 days. I even started adding in the code myself in a GitHub PR. I then discovered that the Android companion app does allow user added certificates.

The fix for me was to go to the Home Assistant app info in android and clear the cache and storage to have a clean start. After opening the app it accepted my new https://192.168.1.x:8123 local address where before it failed on boot every time.

My scenario:
Step 1:

mkcert homeassistant.local 192.168.1.x

Step 2: Copy the 2 .pem files to /ssl/ in the home assistant directory (I did this via samba share)
Step 3: Edit configuration.yaml with below and remember to rename the .pem file to what you have

http:
  ssl_certificate: /ssl/homeassistant.local+ip.pem
  ssl_key: /ssl/homeassistant.local+ip-key.pem

Remember that you can now only access your home assistant via https:// and not http:// anymore.
This will now work in browsers but you’ll get a red lock indicating it doesn’t trust your certificate.

Step 4: Run below to find the location of the root cert that you now need to “install” on all your devices to get it to trust your new certificate

mkcert -CAROOT

Step 5: I installed it on my Mac and 2 OnePlus android phones. On android you can just search your settings for install certificates and choose your rootCA.pem file

ALL DONE

For anyone wondering why I went through this trouble. I don’t have port 80 and 443 open to the internet so let’s encrypt, nginx proxy manager, etc can’t verify their certificates so I had to use a self-signed certificate. I prefer to only open 1 port for a VPN service and connect that way to everything in my network which is now working very nicely.

1 Like

Thanks for your post, this is how I did it however as mentioned above the iOS companion app did not want to accept it (CA-Root also had been added to the iPhone certificate store).
Don‘t see an option to empty any cache in the iOS app…

I’m afraid I don’t have an IOS device to test on but I would suggest doing what the mkcert readme says here:


and then deleting the IOS companion app and reinstalling it. Hope that fixes it. Let me know.

The small print I had already done.
Only thing not done was deleting and reinstalling the Companion App. I have my doughs that it helps but I will give it a new attempt on the weekend…

If you have Apple: Here is what worked for me recently in 2022 after forgetting to renew my HA cert, I decided to do the whole process from scratch using a private internal MS CA that my (IOS) devices trust the root cert. I create a cert req file and submit it to the CA, convert it and add it to HA and the IOS devices:

#Create a openssl config file: ha.req.conf

#Start file ha.req.conf

[ req ]
prompt = no
days = 730
distinguished_name = req_dn
req_extensions = v3_req

[ req_dn ]
countryName = US
stateOrProvinceName = NY
localityName = DT
organizationName = MYORG
organizationalUnitName = MYORGNAME
commonName = ha.mypriv.lan
emailAddress = [email protected]

[ v3_req ]
basicConstraints = CA:true
extendedKeyUsage = serverAuth
subjectAltName = @req_sans

[ req_sans ]
#Set some legacy (.local) and current (.lan) SANs for multiple HAs
#Adding more SANs to cover use cases
DNS.0 = localhost
DNS.1 = ha.mypriv.lan
DNS.2 = ha.mypriv.local
DNS.3 = ha
DNS.4 = hassio
DNS.5 = homeassistant
DNS.6 = ha.local
DNS.7 = homeassistant.local
DNS.8 = hassio.local
DNS.9 = hassios

# [ v3_req ]
# extendedKeyUsage = 1.3.6.1.5.5.7.3.1
# 1.3.6.1.5.5.7.3.1 can also be spelled serverAuth:
# extendedKeyUsage = serverAuth
# see x509v3_config for other extensions

#End file ha.req.conf

#Generate the CA request file, remember to backup the privkey.pem if you want to re-use it next time.

openssl req -sha512 -newkey rsa:4096 -keyout privkey.pem -nodes -out ha.req -config ha.req.conf

#Then go to the CA (could be a public one, should work OK):

https://myca01.mypriv.lan/certsrv/certrqxt.asp

#Paste in the contents of the req file and use a webserver template
#Download the certs/chain in Base 64
#Convert certnew.p7b as fullchain.pem

openssl pkcs7 -print_certs -in certnew.p7b -out fullchain.pem

#I choose to remove the Microsoft CA lines from the fullchain.pem
#Its good to make sure moduli match (should see no output)

diff <(openssl x509 -noout -modulus -in fullchain.pem) <(openssl rsa -noout -modulus -in privkey.pem)

#Dont forget to cleanup .ssh folder/update ssh keys on the OS as the keys are changing
#make sure the HA configuration.yaml uses the same ssl path:

http:
#base_url: ha.mypriv.lan:8123
ssl_certificate: /ssl/fullchain.pem
ssl_key: /ssl/privkey.pem

#If replacing an old set of files make sure the new ones have the correct permissions - either paste #privkey.pem contents into the old privkey.pem file on HA (has the correct ownership and permissions) #and the same #with fullchain.pem, or upload the new files and set correct permissions from the HA #console - for example

ssh [email protected] (IP or FQDN)

config $ cd /ssl
ssl $ chown root:root fullchain.pem privkey.pem
ssl $ chmod 600 fullchain.pem privkey.pem
reboot

#Then zip up fullchain.pem as some IOS Apps do not like pem files
#Distribute fullchain.pem.zip via app, copy to local storage (email or Telegram in my case). Add profile #to iPhone and Apple Watch, check in IOS settings for new profiles added then install/approve.
#(Found in settings, general, about, certificate trust settings!!!)

#If on OSX, reset the mDNS
sudo killall -HUP mDNSResponder

1 Like