Edit Dec 2023

Following a move to new hardware, I have updated this post to, hopefully, make things clearer and take into consideration everybody’s comments and difficulties. Many thanks to mwav3-Tim for his brillant support.

Introduction

The Home assistant support team sensibly recommend you use a dedicated system. This simplifies support, but limits your possibility to run other stuff. Many people run Home Assistant using docker but getting remote access seemed to me to be a nightmare.

But there is very simple way to get everything done, including Letsencrypt, NGINX, certificate renewal, duckdns, security etc.

It is a docker package called SWAG and it includes a sample home assistant configuration file that only needs a minor tweak.

A basic understanding of Docker is presumed and that Docker-Compose is installed on your machine.

The configuration is minimal so you can ​get a test system working very quickly. After that, it should be easy to modify your existing configuration.

Rather than upset your production system, I suggest you create a test directory and data volumes;

mkdir ~/swagtest
mkdir ~/swagtest/hass
mkdir ~/swagtest/swag

I have found it simpler to first get the basic system running to test and understand a little what we have. Then we’ll add Home Assistant.

You’ll need shut down your production system ( eg docker-compose down) while testing. Check with docker ps

Port Forwarding

Set up a static ip address for your home assistant machine on your router. Where you see 192.168.X.XXX in the snippets below , change it to your static address.

Forward port 443 through your router to your home assistant server port 443. No need to forward ports 80 or 8123.

DuckDNS

Set up a Duckdns account. This is simple and fully explained on their web site. Keep a record of “your-domain” and “your-access-token”.

docker-compose.yml

Create a docker-compose.yml configuration file as show below for the basic SWAG.

Since docker creates some files as root, you will need your PUID & GUID ( just use the Unix command ‘id’ to find these). The #! indicates change required ( eg your duckdns info ).

version: "3"
services:
  
swag:
    image: ghcr.io/linuxserver/swag
    container_name: swag
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1001                   #!
      - PGID=1001                   #!
      - TZ=Europe/Paris             #!
      - URL=YOUR-DOMAIN.duckdns.org #!
      - VALIDATION=duckdns
      - DUCKDNSTOKEN=YOUR-TOKEN     #!
      - SUBDOMAINS=wildcard
    volumes:
      - ~/swagtest/swag:/config     #!
    ports:
      - 443:443
    restart: unless-stopped

SWAG first run

To set up SWAG, run

docker-compose up swag

This will download the swag image, create the swag volume, unpack and set up the default configuration. It will take some time to generate the certificates etc.

If all goes well, it should end with

swag [services.d] starting services
swag [services.d] done.
swag Server ready.

Test external access

SWAG has set up a little test web page, you should be able to access it externally (eg on a phone, turn off wifi and use phone network) by typing it’s address into your web browser: https:\www.YOUR-DOMAIN.duckdns.org

If that works, good; certificates, duckdns renewal, port forwarding etc are good to go. If not, check everything for typos. This works for me and others, it should work for you unless you have a weird setup.

If you get warnings about the site being unsafe, I think this is caused by Let’s Encrypt throttling multiple unsuccessful attempts to validate. Wait a while, warnings should go away.

Shut down the SWAG docker dialog gracefully using ctrl-C

Set up Home assistant

Now we want to include home assistant.

There are a couple of things that need to be done.

1) Tell SWAG we want to use home assistant. 2) Tell SWAG the ip address of the home assistant server. 3) Update the docker-compose.yml file to include home assistant and establish a docker network that home assistant can trust. 4) In the home assistant configuration, tell it to accept traffic forwarded to it by SWAG and set up simple ip bans.

1) Activate Home Assistant

SWAG contains lots of pre-configured example configuration files, including for home assistant.

In the directory ~/swagtest/swag/nginx/proxy-confs/ , make a copy of ‘homeassistant.subdomain.conf.sample` and rename it to ‘homeassistant.subdomain.conf’

2) Home assistant IP address

Usually, docker sets up its own network and can connect to the home assistant container. But homeassistant must use mode ‘host’ to connect to everything. So the configuration file needs to be given the static IP address of your server .

So the ip address needs to be entered in the file ‘/home/user/test/volumes/swag/nginx/proxy-confs/homeassistant.subdomain.conf’. The two lines set $upstream_app homeassistant; need to be changed to your static host address set $upstream_app 192.168.X.XXX;

The two lines are a bit difficult to find. This is the homeassistant.subdomain.conf file (with all # comments removed for clarity)

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name homeassistant.*;
    include /config/nginx/ssl.conf;
    client_max_body_size 0;
    location / {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app 192.168.XX.XXX;
        set $upstream_port 8123;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
        location /api {
        include /config/nginx/proxy.conf;
        include /config/nginx/resolver.conf;
        set $upstream_app 192.168.XX.XXX;
        set $upstream_port 8123;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }
}

3) Update docker-compose.yml

In the docker-compose.yml file, we need to specify a docker network so home assistant knows what to trust and add the normal home assistant service.

version: '3'

# Set the default docker network to have a known range so it can be trusted by home assistant.
networks:
  default:
      ipam:  
        config: 
         - subnet: 172.10.0.0/24

services:
  hass:
    container_name: hass
    image: homeassistant/home-assistant
    volumes:
      - ~/swagtest/hass:/config  # Change this
      - /etc/localtime:/etc/localtime:ro
# Note: Port mapping is no longer valid with network_mode host
#    ports:
#      - 8123:8123
    network_mode: host
    restart: unless-stopped
    
swag:
    image: ghcr.io/linuxserver/swag
    container_name: swag
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1001  # Change this
      - PGID=1001  # Change this
      - TZ=Europe/Paris
      - URL=YOUR-DOMAIN.duckdns.org  # Change this
      - VALIDATION=duckdns
      - DUCKDNSTOKEN=YOUR-TOKEN  # Change this
      - SUBDOMAINS=wildcard
    volumes:
      - /home/USER/volumes/swag:/config  # Change this
    ports:
      - 443:443
    restart: unless-stoppeda

Start home assistant to generate the initial configuration for the test

docker-compose up hass

When everything is finished, shut down using crtl-C.

4) Home assistant configuration

Add the following to you home assistant config.yaml ( ~/swagtest/hass/configuration.yaml).

http: ip_ban_enabled: true login_attempts_threshold: 3 use_x_forwarded_for: true trusted_proxies: - 192.168.X.0/24 # Local Lan - 172.10.0.0/24 # Docker network

Finally-Test it is working

Launch homeassistant and swag

docker-compose up -d

Wait a little.

Then, use your browser to logon from your local network 192.168.X.XXX:8123 and you should get your normal home assistant login.

Finally, use your browser to logon from outside your home https://homeassistant.YOUR-SUB-DOMAIN.duckdns.org

Note: unless your router supports ’loopback’ ( and mine didn’t) you might not be able to connect; in that case use a telephone ( or tor browser) rather than your local LAN connection.

That’s it. You have remote access to home assistant.