Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge proxy and funnel options into share_homeassistant, rename proxy_and_funnel_port to share_on_port (nonbreaking change, config is automatically updated) #445

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 46 additions & 58 deletions tailscale/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,10 @@ advertise_connector: true
advertise_routes:
- 192.168.1.0/24
- fd12:3456:abcd::/64
funnel: false
log_level: info
login_server: "https://controlplane.tailscale.com"
proxy: false
proxy_and_funnel_port: 443
share_homeassistant: disabled
share_on_port: 443
snat_subnet_routes: true
stateful_filtering: false
tags:
Expand Down Expand Up @@ -147,48 +146,6 @@ More information: [Subnet routers][tailscale_info_subnets]
When not set, the add-on by default will advertise routes to your subnets on all
supported interfaces.

### Option: `funnel`

This requires Tailscale Proxy to be enabled.

**Important:** See also the "Option: `proxy`" section of this documentation for the
necessary configuration changes in Home Assistant!

When not set, this option is disabled by default.

With the Tailscale Funnel feature, you can access your Home Assistant instance
from the wider internet using your Tailscale domain (like
`https://homeassistant.tail1234.ts.net`) even from devices **without installed
Tailscale VPN client** (for example, on general phones, tablets, and laptops).

**Client** ⇒ _Internet_ ⇒ **Tailscale Funnel** (TCP proxy) ⇒
_VPN_ ⇒ **Tailscale Proxy** (HTTPS proxy) → **HA** (HTTP web-server)

Without the Tailscale Funnel feature, you will be able to access your Home
Assistant instance only when your devices (for example, phones, tablets, and laptops)
are connected to your Tailscale VPN, there will be no Internet ⇒ VPN TCP
proxying for HTTPS communication.

More information: [Tailscale Funnel][tailscale_info_funnel]

1. Navigate to the [Access controls page][tailscale_acls] of the admin console:

- Add the required `funnel` node attribute to the tailnet policy file. See
[Tailnet policy file requirement][tailscale_info_funnel_policy_requirement]
for more information.

1. Restart the add-on.

**Note**: _After initial setup, it can take up to 10 minutes for the domain to
be publicly available._

**Note:** _You should not use the port number in the URL that you used
previously to access Home Assistant. Tailscale Funnel works on the default HTTPS
port 443 (or the port configured in option `proxy_and_funnel_port`)._

**Note:** _If you encounter strange browser behaviour or strange error messages,
try to clear all site related cookies, clear all browser cache, restart browser._

### Option: `log_level`

Optionally enable tailscaled debug messages in the add-on's log. Turn it on only
Expand Down Expand Up @@ -219,26 +176,44 @@ This option lets you to specify a custom control server instead of the default
(`https://controlplane.tailscale.com`). This is useful if you are running your
own Tailscale control server, for example, a self-hosted [Headscale] instance.

### Option: `proxy`
### Option: `share_homeassistant`

This option allows you to enable Tailscale Serve or Funnel features to present
your Home Assistant instance with a valid certificate on your tailnet or
internet.

When not set, this option is disabled by default.

Tailscale can provide a TLS certificate for your Home Assistant instance within
your tailnet domain.

This can prevent browsers from warning that HTTP URLs to your Home Assistant instance
look unencrypted (browsers are not aware of the connections between Tailscale
nodes are secured with end-to-end encryption).
This can prevent browsers from warning that HTTP URLs to your Home Assistant
instance look unencrypted (browsers are not aware that the connections between
Tailscale nodes are secured with end-to-end encryption).

With the Tailscale Serve feature, you can access your Home Assistant instance
with the provided certificate within your tailnet from devices already connected
to your tailnet.

With the Tailscale Funnel feature, you can access your Home Assistant instance
with the provided certificate not only within your tailnet but even from the
wider internet using your Tailscale domain (like
`https://homeassistant.tail1234.ts.net`) from devices **without installed
Tailscale VPN client** (for example, on general phones, tablets, and laptops).

**Client** ⇒ _Internet_ ⇒ **Tailscale Funnel** (TCP proxy) ⇒
_VPN_ ⇒ **Tailscale Serve** (HTTPS proxy) → **HA** (HTTP web-server)

More information: [Enabling HTTPS][tailscale_info_https]
More information: [Enabling HTTPS][tailscale_info_https], [Tailscale
Serve][tailscale_info_serve], [Tailscale Funnel][tailscale_info_funnel]

1. Configure Home Assistant to be accessible through an HTTP connection (this is
the default). See [HTTP integration documentation][http_integration] for more
information. If you still want to use another HTTPS connection to access Home
Assistant, please use a reverse proxy add-on.

1. Home Assistant, by default, blocks requests from reverse proxies, like the
Tailscale Proxy. To enable it, add the following lines to your
Tailscale Serve. To enable it, add the following lines to your
`configuration.yaml`, without changing anything:

```yaml
Expand All @@ -256,17 +231,29 @@ More information: [Enabling HTTPS][tailscale_info_https]

- Under HTTPS Certificates section, click Enable HTTPS.

1. Optionally, if you want to use Tailscale Funnel, navigate to the [Access
controls page][tailscale_acls] of the admin console:

- Add the required `funnel` node attribute to the tailnet policy file. See
[Tailnet policy file requirement][tailscale_info_funnel_policy_requirement]
for more information.

1. Restart the add-on.

**Note:** _You should not use the port number in the URL that you used
previously to access Home Assistant. Tailscale Proxy works on the default HTTPS
port 443 (or the port configured in option `proxy_and_funnel_port`)._
**Note**: After initial setup, it can take up to 10 minutes for the domain to
be publicly available.

**Note:** You should not use the port number in the URL that you used
previously to access Home Assistant. Tailscale Serve and Funnel works on the
default HTTPS port 443 (or the port configured in option `share_on_port`).

**Note:** If you encounter strange browser behaviour or strange error messages,
try to clear all site related cookies, clear all browser cache, restart browser.

### Option: `proxy_and_funnel_port`
### Option: `share_on_port`

This option allows you to configure the port the Tailscale Proxy and Funnel
features are accessible on the tailnet (in case of Tailscale Proxy is enabled)
and optionally on the internet (in case of Tailscale Funnel is also enabled).
This option allows you to configure the port the Tailscale Serve and Funnel
features are accessible on the tailnet and internet.

Only port number 443, 8443 and 10000 is allowed by Tailscale.

Expand Down Expand Up @@ -428,6 +415,7 @@ SOFTWARE.
[tailscale_info_funnel_policy_requirement]: https://tailscale.com/kb/1223/funnel#requirements-and-limitations
[tailscale_info_https]: https://tailscale.com/kb/1153/enabling-https
[tailscale_info_key_expiry]: https://tailscale.com/kb/1028/key-expiry
[tailscale_info_serve]: https://tailscale.com/kb/1312/serve
[tailscale_info_site_to_site]: https://tailscale.com/kb/1214/site-to-site
[tailscale_info_subnets]: https://tailscale.com/kb/1019/subnets
[tailscale_info_tags]: https://tailscale.com/kb/1068/tags
Expand Down
5 changes: 2 additions & 3 deletions tailscale/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,10 @@ schema:
advertise_connector: bool?
advertise_routes:
- "match(^(((25[0-5]|(2[0-4]|1\\d|[1-9]?)\\d)\\.){3}(25[0-5]|(2[0-4]|1\\d|[1-9]?)\\d)\\/(3[0-2]|[12]?\\d)|[a-fA-F\\d.:]+:[a-fA-F\\d.:]+\\/(12[0-8]|(1[01]|[1-9]?)\\d))$)?"
funnel: bool?
log_level: list(trace|debug|info|notice|warning|error|fatal)?
login_server: url?
proxy: bool?
proxy_and_funnel_port: match(^(443|8443|10000)$)?
share_homeassistant: list(disabled|serve|funnel)?
share_on_port: match(^(443|8443|10000)$)?
snat_subnet_routes: bool?
stateful_filtering: bool?
tags:
Expand Down
4 changes: 2 additions & 2 deletions tailscale/rootfs/etc/s6-overlay/s6-rc.d/post-tailscaled/run
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@ then
fi

# Delete previously created persistent tailscale serve configuration ONCE
# After add-on's serve (proxy and funnel) service is a longrun service, we do not modify the serve state permanently
# After the add-on's share-homeassistant (serve and funnel) service is a longrun service, we do not modify the serve state permanently
# This step can be removed in a later version with the file in the data folder also
if ! bashio::fs.file_exists "/data/final_serve_reset_is_done"; then
if ! /opt/tailscale serve reset; then
bashio::log.error "Unable to remove previous Tailscale Proxy and Funnel settings"
bashio::log.error "Unable to remove previous Tailscale Serve and Funnel settings"
bashio::exit.nok
fi
touch "/data/final_serve_reset_is_done"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
# shellcheck shell=bash
# ==============================================================================
# Home Assistant Community Add-on: Tailscale
# Take down the S6 supervision tree when Serve fails
# Take down the S6 supervision tree when share-homeassistant fails
# ==============================================================================
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
readonly exit_code_service="${1}"
readonly exit_code_signal="${2}"
readonly service="serve"
readonly service="share-homeassistant"

bashio::log.info \
"Service ${service} exited with code ${exit_code_service}" \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
# shellcheck shell=bash
# ==============================================================================
# Home Assistant Community Add-on: Tailscale
# Enables Tailscale Proxy and Funnel feature
# Enables Tailscale Serve or Funnel feature to share Home Assistant
# ==============================================================================

declare wait_counter=0
declare curl_result
declare tailscale_command

# Validate share_homeassistant value
if ! bashio::config.equals 'share_homeassistant' 'serve' && \
! bashio::config.equals 'share_homeassistant' 'funnel'
then
bashio::log.error "Invalid value '$(bashio::config 'share_homeassistant')' for share_homeassistant. Must be either 'serve' or 'funnel'"
bashio::exit.nok
fi

# Check if Tailscale HTTPS is enabled
if ! /opt/tailscale status --self=true --peers=false --json \
Expand Down Expand Up @@ -44,23 +51,20 @@ else
# Test Home Assistant's HTTP reverse proxy configuration
if (( 200 != $(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:$(bashio::core.port)" -H "X-Forwarded-For: 127.0.0.1") )); then
bashio::log.error "Unable to connect to Home Assistant as reverse proxy"
bashio::log.error "Please check your configuration based on the add-on's documentation under \"Option: proxy\""
bashio::log.error "Please check your configuration based on the add-on's documentation under \"Option: share_homeassistant\""
bashio::exit.nok
fi
fi

if ! bashio::config.true 'funnel'; then
tailscale_command=serve
else
# Check if Funnel is available
# Check if Funnel is available
if bashio::config.equals 'share_homeassistant' 'funnel'; then
if ! /opt/tailscale status --self=true --peers=false --json \
| jq -rce '.Self.CapMap | has("funnel")' > /dev/null;
then
bashio::log.error "Tailscale's Funnel support is disabled"
bashio::exit.nok
fi
tailscale_command=funnel
fi

# Set up serve
exec /opt/tailscale ${tailscale_command} --https=$(bashio::config "proxy_and_funnel_port" "443") --set-path=/ "http://127.0.0.1:$(bashio::core.port)"
# Set up serve or funnel
exec /opt/tailscale $(bashio::config 'share_homeassistant') --https=$(bashio::config 'share_on_port' '443') --set-path=/ "http://127.0.0.1:$(bashio::core.port)"
72 changes: 69 additions & 3 deletions tailscale/rootfs/etc/s6-overlay/scripts/stage2_hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,70 @@
# S6 Overlay stage2 hook to customize services
# ==============================================================================

declare options
declare proxy funnel proxy_and_funnel_port
declare share_homeassistant share_on_port

# This is to execute potentially failing supervisor api functions within conditions,
# where set -e is not propagated inside the function and bashio relies on set -e for api error handling
function try {
set +e
(set -e; "$@")
declare -gx TRY_ERROR=$?
set -e
}

# Load add-on options, even deprecated one to upgrade
options=$(bashio::addon.options)

# Upgrade configuration from 'proxy', 'funnel' and 'proxy_and_funnel_port' to 'share_homeassistant' and 'share_on_port'
# This step can be removed in a later version
proxy=$(bashio::jq "${options}" '.proxy | select(.!=null)')
funnel=$(bashio::jq "${options}" '.funnel | select(.!=null)')
proxy_and_funnel_port=$(bashio::jq "${options}" '.proxy_and_funnel_port | select(.!=null)')
share_homeassistant=$(bashio::jq "${options}" '.share_homeassistant | select(.!=null)')
share_on_port=$(bashio::jq "${options}" '.share_on_port | select(.!=null)')
# Upgrade to share_homeassistant
if bashio::var.true "${proxy}"; then
if bashio::var.has_value "${share_homeassistant}"; then
bashio::log.warning "The proxy and funnel options are already migrated to share_homeassistant option, do not configure deprecated options, proxy and funnel options are dropped."
else
if bashio::var.true "${funnel}"; then
bashio::addon.option 'share_homeassistant' 'funnel'
bashio::log.info "Successfully migrated proxy and funnel options to share_homeassistant: funnel"
else
bashio::addon.option 'share_homeassistant' 'serve'
bashio::log.info "Successfully migrated proxy and funnel options to share_homeassistant: serve"
fi
fi
fi
# Upgrade to share_on_port
if bashio::var.has_value "${proxy_and_funnel_port}"; then
if bashio::var.has_value "${share_on_port}"; then
bashio::log.warning "The proxy_and_funnel_port option is already migrated to share_on_port option, do not configure deprecated options, proxy_and_funnel_port option is dropped."
else
try bashio::addon.option 'share_on_port' "^${proxy_and_funnel_port}"
if ((TRY_ERROR)); then
bashio::log.warning "The proxy_and_funnel_port option value '${proxy_and_funnel_port}' is invalid, proxy_and_funnel_port option is dropped, using default port."
else
bashio::log.info "Successfully migrated proxy_and_funnel_port option to share_on_port: ${proxy_and_funnel_port}"
fi
fi
fi
# Remove previous options
if bashio::var.has_value "${proxy}"; then
bashio::log.info 'Removing deprecated proxy option'
bashio::addon.option 'proxy'
fi
if bashio::var.has_value "${funnel}"; then
bashio::log.info 'Removing deprecated funnel option'
bashio::addon.option 'funnel'
fi
if bashio::var.has_value "${proxy_and_funnel_port}"; then
bashio::log.info 'Removing deprecated proxy_and_funnel_port option'
bashio::addon.option 'proxy_and_funnel_port'
fi

# Disable protect-subnets service when userspace-networking is enabled or accepting routes is disabled
if ! bashio::config.has_value "userspace_networking" || \
bashio::config.true "userspace_networking" || \
Expand All @@ -26,7 +90,9 @@ if bashio::config.false 'taildrop'; then
rm /etc/s6-overlay/s6-rc.d/user/contents.d/taildrop
fi

# Disable serve service when proxy and/or funnel has not been explicitly enabled
if ! bashio::config.true 'proxy'; then
rm /etc/s6-overlay/s6-rc.d/user/contents.d/serve
# Disable share-homeassistant service when share_homeassistant has not been explicitly enabled
if ! bashio::config.has_value 'share_homeassistant' || \
bashio::config.equals 'share_homeassistant' 'disabled'
then
rm /etc/s6-overlay/s6-rc.d/user/contents.d/share-homeassistant
fi
24 changes: 9 additions & 15 deletions tailscale/translations/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ configuration:
your device is connected to) to other clients on your tailnet.
When not set, the add-on by default will advertise routes to your subnets on all
supported interfaces.
funnel:
name: Tailscale Funnel
description: >-
This option allows you to enable Tailscale's Funnel feature to present your
Home Assistant instance on the wider internet using your Tailscale domain.
This requires Tailscale Proxy to be enabled.
When not set, this option is disabled by default.
log_level:
name: Log level
description: >-
Expand All @@ -52,17 +45,18 @@ configuration:
This option allows you to specify a custom control server for this
Tailscale instance, for example, a self-host Headscale instance.
By default, it uses the control server provided by Tailscale.
proxy:
name: Tailscale Proxy
share_homeassistant:
name: Share Home Assistant with Serve or Funnel
description: >-
This option allows you to enable Tailscale's Proxy feature to present your
Home Assistant instance on your tailnet with a valid certificate.
This option allows you to enable Tailscale Serve or Funnel features to present
your Home Assistant instance with a valid certificate on your tailnet or
internet.
When not set, this option is disabled by default.
proxy_and_funnel_port:
name: Tailscale Proxy and Funnel port
share_on_port:
name: Share on port
description: >-
This option allows you to configure the port the Tailscale Proxy and Funnel
features are accessible on.
This option allows you to configure the port the Tailscale Serve and Funnel
features are accessible on the tailnet and internet.
Only port number 443, 8443 and 10000 is allowed by Tailscale.
snat_subnet_routes:
name: Source NAT subnet routes
Expand Down
Loading