Mimicking Home Assistant Ingress On DOCKER!

I am sorry if this is something obvious; I have had Home Assistant for about a week now and I hadn’t found this out, hence I am adding it to the wiki/forum. I’ve found two ways that I think are pretty cool (at least in a “geeky” sense).

The Setup

First, I should mention that I am using Caddy. I love it because it’s simple and secure—you really can’t ask for much more. I also use Cloudflare alongside it. While this isn’t a dedicated Caddy guide, here is my base configuration:

Code snippet

# Home Assistant
home.redacted.gr {
  import tls_cloudflare
  import static_robots
  encode gzip zstd

  # --- Home Assistant ---
  reverse_proxy localhost:8123 {
    header_up Host {host}
    header_up X-Forwarded-Host {host}
    header_up X-Real-IP {remote_ip}
  }

  log {
    output file /var/log/caddy/home.log
  }
}

This gives you the basic foundation you need. Now, let’s get to the juicy stuff. There are two ways to mimic the “Ingress” behavior found in Home Assistant OS.


Option 1: The Caddy Subpath Method

This was my original approach. You essentially create a reverse proxy within a reverse proxy by using handle_path.

The Config:

Code snippet

# --- Portainer ---
handle_path /portainer* {
    reverse_proxy 192.168.1.54:9000 {
        # Tells the app it is living behind the /portainer prefix
        header_up X-Forwarded-Prefix "/portainer"
        
        # Allows the app to be framed by your HA URL
        header_down Content-Security-Policy "frame-ancestors 'self' https://home.redacted.gr"
    }
}

Your final Caddyfile should look something like this:

Code snippet

# Home Assistant
home.redacted.gr {
  import tls_cloudflare
  import static_robots
  encode gzip zstd
  
  # --- Portainer ---
  handle_path /portainer* {
    reverse_proxy 192.168.1.54:9000 {
      # Tells the app it is living behind the /portainer prefix
      header_up X-Forwarded-Prefix "/portainer"
      
      # Allows the app to be framed by your HA URL
      header_down Content-Security-Policy "frame-ancestors 'self' https://home.redacted.gr"
    }
  }

  # --- Home Assistant Proxy ---
  reverse_proxy localhost:8123 {
    header_up Host {host}
    header_up X-Forwarded-Host {host}
    header_up X-Real-IP {remote_ip}
  }

  log {
    output file /var/log/caddy/home.log
  }
}

When you integrate this into your main config, you can then create an iFrame in your Home Assistant dashboard. Add your URL in this exact format (the trailing slash is crucial):

https://home.redacted.gr/portainer/


Option 2: The hass_ingress Method (Recommended)

I eventually found a better way, although some might argue it’s slightly harder to set up. There is a repository called hass_ingress by lovelylain that provides a more “built-in” feel.

You will need HACS installed to use this. While it offers a ton of customizability, here is how you would replicate the Portainer example in your configuration.yaml:

YAML

# Ingress settings for hass_ingress
ingress:
  portainer:
    title: "Portainer"
    icon: "mdi:docker"
    url: "http://192.168.1.54:9000"
    work_mode: ingress
    ui_mode: normal
    rewrite:
      # This replaces the Caddy 'header_down' logic
      - mode: header
        name: "Content-Security-Policy"
        match: "frame-ancestors.*"
        replace: "frame-ancestors 'self' https://home.redacted.gr"

  nodered:
    title: "Node-RED"
    icon: "mdi:sitemap"
    url: "http://192.168.1.54:1880"
    work_mode: ingress
    ui_mode: normal

Note: The security headers (CSP) are often specific to the app. For example, while Portainer required the rewrite logic, Node-RED worked fine without it.

Reloading the Configuration

After adding this to your YAML, you don’t need to restart HA:

  1. Go to Developer Tools.

  2. Go to the YAML tab.

  3. Under “YAML configuration reloading,” click on Ingress.

You are DONE!


Why Option 2 is better:

The main benefit of using hass_ingress is that you aren’t actually exposing these services to the web (not even under a subpath on Caddy). It keeps everything internal to Home Assistant, allowing you to technically use the same authentication session and even embed credentials—though I haven’t fully explored that last part yet!

2 Likes