Remote Access for Home Assistant container with DDNS provided by ISP and NGINX

This will be my first post, so please bear with me :slight_smile: . I have discovered the Home Assistant community only a couple of weeks ago and I decided on the container install method because it is a little work related and new learning opportunity. A lot to unpack to say the least. I got things up and running already with the exception of the remote access, at least partially.

Here is my situation: I have a DDNS provided by my ISP that provides me with a domain, and only that, no access token, I have asked, and I have a NGINX webserver that is already acting as a homepage for my other services that I have running: Sonarr, Radarr etc. NGINX config has been done by a friend of mine, so I have very little knowhow with it. All is know that ports 80 and 443 are already pointing to it.

I want to put the access to Home Assistant behind the same webserver, I read that it does not support using a path External_URL

I have remote access if I forward port 8123, but it is unsecured.

I have a couple of the guides here in the community, but it didn’t help me very much with my situation, I admit there are a lot of things that I am unaware of.

Any kind of help would be greatly appreciated. And if other info is required.

Thank you!

This is my running NGINX config.

##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
	listen 80 default_server;
	listen [::]:80 default_server;

	# SSL configuration
	#
	# listen 443 ssl default_server;
	# listen [::]:443 ssl default_server;
	#
	# Note: You should disable gzip for SSL traffic.
	# See: https://bugs.debian.org/773332
	#
	# Read up on ssl_ciphers to ensure a secure configuration.
	# See: https://bugs.debian.org/765782
	#
	# Self signed certs generated by the ssl-cert package
	# Don't use them in a production server!
	#
	# include snippets/snakeoil.conf;

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name _;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

	# pass PHP scripts to FastCGI server
	#
	#location ~ \.php$ {
	#	include snippets/fastcgi-php.conf;
	#
	#	# With php-fpm (or other unix sockets):
	#	fastcgi_pass unix:/run/php/php7.4-fpm.sock;
	#	# With php-cgi (or other tcp sockets):
	#	fastcgi_pass 127.0.0.1:9000;
	#}

	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#
	#location ~ /\.ht {
	#	deny all;
	#}
}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#	listen 80;
#	listen [::]:80;
#
#	server_name example.com;
#
#	root /var/www/example.com;
#	index index.html;
#
#	location / {
#		try_files $uri $uri/ =404;
#	}
#}

server {

	# SSL configuration
	#
	# listen 443 ssl default_server;
	# listen [::]:443 ssl default_server;
	#
	# Note: You should disable gzip for SSL traffic.
	# See: https://bugs.debian.org/773332
	#
	# Read up on ssl_ciphers to ensure a secure configuration.
	# See: https://bugs.debian.org/765782
	#
	# Self signed certs generated by the ssl-cert package
	# Don't use them in a production server!
	#
	# include snippets/snakeoil.conf;

	root /var/www/html;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;
    server_name mydomain; # managed by Certbot

    location /sonarr {
        proxy_pass http://localhost:8989/sonarr;
    }

    location /radarr {
        proxy_pass http://localhost:7878/radarr;
    }

    location /readarr {
        proxy_pass http://localhost:8787/readarr;
    }

    location /lidarr {
        proxy_pass http://localhost:8686/lidarr;
    }

    location /prowlarr {
        proxy_pass http://localhost:9696/prowlarr;
    }

    location ^~ /overseerr {
        set $app 'overseerr';
	rewrite ^/overseerr/?(.*)$ /$1 break;
        proxy_pass http://localhost:5055;

	 # Redirect location headers
        proxy_redirect ^ /$app;
        proxy_redirect /setup /$app/setup;
        proxy_redirect /login /$app/login;

        # Sub filters to replace hardcoded paths
        proxy_set_header Accept-Encoding "";
        sub_filter_once off;
        sub_filter_types *;
        sub_filter 'href="/"' 'href="/$app"';
        sub_filter 'href="/login"' 'href="/$app/login"';
        sub_filter 'href:"/"' 'href:"/$app"';
        sub_filter '\/_next' '\/$app\/_next';
        sub_filter '/_next' '/$app/_next';
        sub_filter '/api/v1' '/$app/api/v1';
        sub_filter '/login/plex/loading' '/$app/login/plex/loading';
        sub_filter '/images/' '/$app/images/';
        sub_filter '/android-' '/$app/android-';
        sub_filter '/apple-' '/$app/apple-';
        sub_filter '/favicon' '/$app/favicon';
        sub_filter '/logo_' '/$app/logo_';
        sub_filter '/site.webmanifest' '/$app/site.webmanifest';
    }

    location /deluge {
        proxy_pass http://localhost:8112/;
        proxy_set_header X-Deluge-Base "/deluge/";
        add_header X-Frame-Options SAMEORIGIN;
    }

#    location / {
    	#sub_filter 'src=/static/' 'src=/haas/static/';
	#sub_filter 'src=/hacs-files/' 'src=/haas/hacs-files/';
	#sub_filter_once off;
#        proxy_pass http://127.0.0.1:8123;
#	proxy_pass http://localhost:8123/lovelace/0;
#        proxy_set_header Host $host;
#        proxy_redirect http:// https://;
#        proxy_http_version 1.1;
#        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#        proxy_set_header Upgrade $http_upgrade;
#	proxy_set_header Connection "upgrade";
#    }
	# pass PHP scripts to FastCGI server
	#
	#location ~ \.php$ {
	#	include snippets/fastcgi-php.conf;
	#
	#	# With php-fpm (or other unix sockets):
	#	fastcgi_pass unix:/run/php/php7.4-fpm.sock;
	#	# With php-cgi (or other tcp sockets):
	#	fastcgi_pass 127.0.0.1:9000;
	#}

	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#
	#location ~ /\.ht {
	#	deny all;
	#}
	
    


    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/mydomain/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/mydomain/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = mydomain) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


	listen 80 ;
	listen [::]:80 ;
    server_name mydomain;
    return 404; # managed by Certbot


}

Docker compose config

version: '3'
services:
  homeassistant:
    container_name: homeassistant
    image: "ghcr.io/home-assistant/home-assistant:stable"
    volumes:
      - /opt/hass:/config
      - /etc/localtime:/etc/localtime:ro
      - /run/dbus:/run/dbus:ro
    restart: unless-stopped
    privileged: true
    network_mode: host

You can use cloudflare for tunneling and it does work in docker compose. It doesn’t require any port forwarding. I set it up a few months ago and shut it down after few hours. Why? I saw that I had nearly hounded connection attempts from mostly USA, China and Russia.
I didn’t feel conformable with this and I shut everything down, because I’m not sure that my setup is bulletproof.
I don’t suggest you to do setup you intend to do unless you are absolutely sure in things you are doing.
For remote access use nabu casa. I think it’s a small price for a peaceful piece of mind.

That doesn’t provide any more security than DIY.

If you want to cut down on random probes simply using a random port (something in the 10,000 to 65,535 range) will help.

HA can’t work with a path, it needs to be the entire host. Either a separate hostname, or another port.

As I’m not it pro than a guy that learned from doc without any real life experience, except my own configuration, I will still pass. For now. I now that there is a lot of things I don’t know or know poorly, especially docker security. I could expose my ha instance and make some stupid mistake.
Nabu casa is still idiot proof solution, by some extent.

Thank you for confirming what I was thinking.

When you say hostname, you mean another domain, right? Also, another port is referring to another port for HTTPS?

Thank you for the reply, let’s say that paying for another service is not an option. Trying to do it as free as possible.

No problem. It’s your system. Do with it what you want.

Yes, and yes

For instance you could use https://yourhost.example.org for everything except HA, and https://yourhost.example.org:12345 for HA.

1 Like

If it helps, I use no-ip.com
I use a free host name I created with them, I then use a container to update them with my dynamic IP and thus host name. Lastly I have I have a wireguard container that provides me vpn access to my home. I use the android or windows barcode generated by wireguard to configure these clients, so when I am away from home I run the client, it connects to my no-ip host name that is aware of my dynamic ip address and connects to my VPN. I then have access to my HA instance as well as my local lan.

1 Like