Accessing Home Assistant from the Internet
29 Apr 2023Home Assistant is an open-source home automation platform that allows you to control and automate various aspects of your home, such as lighting, temperature, security, and entertainment systems. It is designed to work with a wide range of devices and platforms, including smart speakers, sensors, cameras, and other Internet of Things (IoT) devices.
In this article I will present how to set up secure remote access for Home Assistant local installation.
Plan
Before we begin opening our Home Assistant installation to the world, it is necessary to ensure that our connection is properly secured. Additionally, it would be a significant advantage if we could access it both locally (i.e., on the local LAN or Wi-Fi) and remotely, in an instantly interchangeable way (without taking any additional steps, such as connecting to a VPN).
To achieve the above, I will use Nginx as an authenticated SSL/TLS reverse proxy that will handle all incoming requests, and a technique called DNS spoofing, for convenient switching between local and remote connections.
Spoof external domain with local DNS
Once the external domain is known, it will need to be spoofed with the local DNS. The requirement here is that we have control of the DNS used in our local LAN or Wi-Fi. The easiest method is to modify /etc/hosts
on our router and/or machine (laptop or phone).
Assuming that our domain is home.example.com
and our Home Assistant installation runs on a machine with the IP address 192.168.1.2
, the configuration could look like this:
/etc/hosts
192.168.2.1 home.example.com
On a machine connected to the local LAN, the above configuration can be tested with the following command:
dig home.example.com
The response should return something like:
;; QUESTION SECTION:
;home.example.com. IN A
;; ANSWER SECTION:
home.example.com. 0 IN A 192.168.1.2
The next step is to set up an Nginx reverse proxy, which will handle incoming requests that come to home.example.com
.
Create nginx reverse proxy
Nginx is a powerful web server and reverse proxy server that can act as an intermediary between client devices and backend servers.
The installation process varies among different Linux distributions, and for the rest of this article, I will assume that we have a running server, preferably on the same machine as Home Assistant.
An example of a default configuration could look like this:
/etc/nginx/nginx.conf
# Defines the number of worker processes.
worker_processes auto;
events {}
http {
# Include the mime.types file, which contains mappings of file extensions
# to their corresponding MIME types.
include mime.types;
# Defines the default MIME type of a response
default_type application/octet-stream;
# Enables or disables the use of sendfile() system call to serve static files.
sendfile on;
# Sets the maximum size of the types hash tables.
types_hash_max_size 4096;
# Enables or disables emitting nginx version on error pages and in the “Server”
# response header field.
server_tokens off;
# Enable access log
access_log /var/log/nginx/access.log;
# Include server specific files
include /etc/nginx/conf.d/*.conf;
}
And the one corresponding to home assistant host:
/etc/nginx/conf.d/home.conf
server {
listen 80;
server_name home.example.com;
proxy_buffering off;
proxy_set_header Connection upgrade;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
location / {
proxy_pass http://localhost:8123;
}
}
We would also need to change the default Home Assistant configuration (the assumption here is that Home Assistant runs on the same machine as nginx):
/var/lib/home_assistant/configuration.yaml
http:
use_x_forwarded_for: true
trusted_proxies:
- 127.0.0.1
We can then access home assistant installation at http://home.example.com
.
However, there are a few drawbacks here. The endpoint is served on port 80 and does not offer any encryption. Additionally, our Home Assistant installation may be vulnerable to brute force attacks, in which attackers attempt to guess our username and password.
Secure connection with SSL/TLS
To secure a connection, SSL/TLS encryption can be used. To achieve this, a self-signed certificate will be employed.
First, a new RSA private key and a Certificate Signing Request (CSR) for an SSL/TLS certificate need to be generated. This can be done with the OpenSSL command-line tool. For simplicity private key won’t be encrypted with passphrase (nodes
flag). Additionally, the key size will be set to 4096 bits with rsa:4096
:
openssl req -new -newkey rsa:4096 -nodes -keyout home.key -out home.csr
Then, using the same tool a self-signed X.509 SSL/TLS certificate can be generated.
openssl x509 -req -sha256 -days 3650 -in home.csr -signkey home.key -out home.crt -extfile openssl.ini
Where extfile
flag consist SAN (Subject Alternative Name) extension contents. This is mostly required for Chrome browser compatibility.
Contents of openssl.ini
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:TRUE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEnciph
subjectAltName = DNS:example.com, DNS:*.example.com
issuerAltName = issuer:copy
For additional security we could also generate dhparam file
openssl dhparam -out dhparam.pem 4096
Once the home.crt
file is generated, it should be transferred as a trusted authority to all devices that will be accessing the installation. This step is necessary to avoid browser warnings when accessing the home assistant URL. I’ve also observed that this is required for the mobile app.
SSL Client certificate authentication
While TLS/SSL encryption is a robust security protocol that safeguards the transmission of data between a client and server by encrypting the data, it primarily ensures the authenticity of the server to the client. However, this isn’t enough because the server does not have the same assurance about the client. This is where SSL client authentication comes in. It acts as a two-way handshake, ensuring both parties can trust each other, not just the client trusting the server.
Create server ssl certificate
First, server ssl certificate for client authorization needs to be created. It can be done with the following command:
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -subj '/CN=example.com' -keyout home_client.key -out home_client.crt
Once it is generated, we can update nginx configuration that reflects SSL changes:
/etc/nginx/conf.d/home.conf
server {
listen 443 ssl http2;
server_name home.example.com;
add_header Strict-Transport-Security "max-age=63072000" always;
ssl_protocols TLSv1.3;
ssl_certificate /etc/nginx/ssl/home.crt;
ssl_certificate_key /etc/nginx/ssl/home.key;
ssl_client_certificate /etc/nginx/ssl/home_client.crt;
ssl_verify_client on;
ssl_session_cache shared:SSL:10m;
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
proxy_buffering off;
proxy_set_header Connection upgrade;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
location / {
proxy_pass http://localhost:8123;
}
}
Now, when trying to access our home assistant installation a “400 Bad Request” error should be served.
In order to access the server, a client device needs to provide a signed ssl certificate.
Create client ssl certificate
Each device that will access nginx reverse proxy needs to provide (preferably) own ssl client certificate that was signed with server certificate and key (home_client.crt
and home_client.key
generated in previous step). The process consists of 3 steps.
Create client key and certificate signing request (csr):
openssl req -new -newkey rsa:4096 -nodes -keyout client.key -out client.csr
Generate ssl client certificate using home_client.key
and home_client.crt
(valid for 10 years):
openssl x509 -req -sha256 -days 3650 -in client.csr -CA home_client.crt -CAkey home_client.key -out client.crt
This step is not required, however to ease the transfer of the files to the device, the client.crt
and client.key
will be packed into client.p12
file:
openssl pkcs12 -legacy -export -inkey client.key -in client.crt -out client.p12
Once client.p12
is generated it can be transfered to the client device.
Transfer certificate to client
Transferring the client.p12
file is a crucial step. This should be accomplished via a local network and/or a physical connection (e.g., USB). For security reasons, copying this file remotely over the internet should be avoided.
The installation process for the p12 file can vary between devices, but for convenience, it could be transferred to a mobile phone (for use with the native home assistant app) and/or a laptop browser (like Chrome).
Once this step is completed, we can access https://home.example.com
. The browser or app should prompt for certificate confirmation. After validation, we should be able to see the home page.
Point ISP IP to the external domain
Once the home assistant installation is secured, it’s time to consider opening it up for global access.
If your Internet Service Provider (ISP) assigns you a static IP address, you can simply create an A record in your domain’s DNS settings. For instance, here’s how it can be done:
home.example.com. 60 IN A 8.8.8.8
In this case, home.example.com
is the domain that will direct to our home assistant installation, and 8.8.8.8
is our external IP address.
However, in many scenarios, the external IP is dynamic, which means that the A record
in the DNS settings will need to be updated periodically to accommodate the changing IP. This can be accomplished using a Dynamic DNS service. A host of companies offer this service, including some that provide it free of charge, such as Duck DNS).
Open port on router
By default, incoming SSL traffic arrives via port 443. To intercept this traffic and redirect it to the home assistant installation, certain modifications will be required on your home router.
The setup procedures can differ significantly among various router software. I will demonstrate how this can be accomplished with a router running OpenWRT.
The following entry can be added to the firewall configuration.
/etc/config/firewall
config redirect 'home_assistant'
option src 'wan'
option dest 'lan'
option proto 'tcp'
option src_dport '443'
option dest_ip '192.168.1.2'
option dest_port '443'
option target 'DNAT'
Conclusion
Opening my home assistant to remote access allowed me to monitor and control the setup from anywhere. Even with remote access, the setup remains secure thanks to SSL user certificate authentication, while DNS spoofing ensures a smooth transition between Wi-Fi and cellular networks, offering an advantage over VPN-based solutions.