Home Assistant OS successfully with External Reverse Proxy Apache2 with LetsEncrypt

Hi all. I am a new user. I configure Home Assistant OS successfully with External Reverse Proxy Apache2 with LetsEncrypt.

Version Home Assistant OS : 2024.5.5 (VM proxmox)

IP Home Assistant OS : 192.168.50.10
Local DNS (PfSense) of Home Assistant OS : homeassistant.local

IP Internal Reverse Proxy : 192.168.50.2 (no incoming acces Internet)

IP External Reverse Proxy : 192.168.10.2 (incoming acces Internet)

HA Proxy internal and external: Debian 12
Server version: Apache/2.4.57 (Debian)
Server built: 2023-04-13T03:26:51

Mods enabled :
Essential Loaded Modules:

proxy_module (shared)
proxy_html_module (shared)
proxy_http_module (shared)
proxy_wstunnel_module (shared)
rewrite_module (shared)
ssl_module (shared)

vhost in Internal Reverse Proxy Apache2 :

<IfModule mod_ssl.c>
<VirtualHost 192.168.50.2:443>

 ServerName home.domain.fr

 ServerSignature off
 RewriteEngine on
 SSLProxyEngine on
 SSLEngine on
 ProxyPreserveHost On
 ProxyRequests off
 SSLHonorCipherOrder on

Include /etc/letsencrypt/options-ssl-apache.conf

ProxyPass /api/websocket ws://homeassistant.local:8123/api/websocket
ProxyPassReverse /api/websocket ws://homeassistant.local:8123/api/websocket


  <Location />
    ProxyPass http://homeassistant.local:8123/
    ProxyPassReverse http://homeassistant.local:8123/
    Order allow,deny
    Allow from all
  </Location>

RewriteCond %{HTTP:Upgrade} =websocket [NC]
  RewriteRule /(.*)  ws://homeassistant.local:8123/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket [NC]
  RewriteRule /(.*)  http://homeassistant.local:8123/$1 [P,L]

SSLCertificateFile /etc/letsencrypt/live/home.domain.fr/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/home.domain.fr/privkey.pem
</VirtualHost>
</IfModule>

/etc/letsencrypt/options-ssl-apache.conf :

# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file. Contents are based on https://ssl-config.mozilla.org

SSLEngine on

# Intermediate configuration, tweak to your needs
SSLProtocol             all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDH>
SSLHonorCipherOrder     off
SSLSessionTickets       off

SSLOptions +StrictRequire

# Add vhost name to log entries:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common

My configuration HA OS:

#configuration.yaml:

# Loads default set of integrations. Do not remove.
default_config:

# Load frontend themes from the themes folder
frontend:
  themes: !include_dir_merge_named themes

automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml

homeassistant:
  external_url: "https://home.domain.fr" # ne pas indiquer le port
  internal_url: "http://homeassistant.local:8123" # adresse locale de HA avec le port

http:
  use_x_forwarded_for: true
  trusted_proxies:
    ## My proxie IP
    - 192.168.50.2
   ## My Home Assistant OS IP is 192.168.50.10 (homeassistant.local)

  ip_ban_enabled: false

My internal proxy (192.168.50.2) does not have internet access for incoming.
My external proxy (192.168.10.2) has internet access for incoming.

In my external reverse proxy, for generate LetsEncrypt certificats,
I use certbot in command line like this when i create new subdomain :

First, I create and enable new vhost in my external proxy:

<VirtualHost 192.168.10.2:80>
 ServerName newsubdomain.domain.fr
 ServerSignature off
 RewriteEngine on
 DocumentRoot /var/www/html
</VirtualHost>

I restart apache2 and :
My port 80 is open (i open this port)

certbot certonly --webroot -w /var/www/html -d newsubdomain.domain.fr -n --agree-tos --email [email protected]

after, my port 80 is closed (i close this port)

In crontab, i have :

30 2 15 * * /usr/sbin/renew

renew :

#!/bin/bash

/usr/sbin/firewall
/usr/bin/certbot renew --quiet
#/usr/bin/certbot renew --force-renewal --quiet
/usr/sbin/firewall nohttp
/usr/bin/systemctl restart apache2
/usr/bin/tar --overwrite -czf /etc/letsencrypt.tar.gz -C /etc/ letsencrypt
exit 0

In my internal reverse proxy (192.168.50.2) i have :

In crontab, i have :

30 2 16 * * /usr/sbin/renew_via_proxyexterne

renew_via_proxyexterne:

#!/bin/bash

/usr/sbin/firewall nohttp
/usr/bin/scp 192.168.10.2:/etc/letsencrypt.tar.gz /etc/
cd /etc/
/usr/bin/tar -xzf letsencrypt.tar.gz
/usr/bin/systemctl restart apache2
exit 0

/usr/sbin/firewall :

#!/bin/bash

/usr/sbin/ufw default allow incoming
/usr/sbin/ufw default allow outgoing


if [ "${1}" == "nohttp" ]; then
 /usr/sbin/ufw deny 80
else
 /usr/sbin/ufw allow 80
fi

/usr/sbin/ufw  -f enable
/usr/sbin/ufw status verbose

exit 0

The PfSense is configured so that the 192.168.50.0/24 network has access to the 192.168.10.0/24 network but not vice versa.

This therefore allows me, behind my PfSense firewall, to have virtual machines that are not accessible via the Internet with an SSL certificate (https) that is still valid and renewed every 16th of the month if necessary.

If I want to access my Home Assistant from outside (outside my Internet box), I use OpenVPN integrated into my PfSense.

I am therefore safe and have great functional freedom.