From 4b86dff3cf0e7d56e045fa94ffe67969ad0e9f1b Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 21 May 2025 00:36:10 -0300 Subject: [PATCH 01/55] Add caddy as internal proxy --- .github/renovate.json | 31 +--- cloudflared/Dockerfile | 28 ++-- cloudflared/build.yaml | 4 - cloudflared/config.yaml | 3 + cloudflared/rootfs/build.sh | 53 +++--- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 16 ++ .../nginx => caddy/dependencies.d/prepare} | 0 .../s6-rc.d/{nginx => caddy}/finish | 20 +-- .../rootfs/etc/s6-overlay/s6-rc.d/caddy/run | 7 + .../s6-overlay/s6-rc.d/{nginx => caddy}/type | 0 .../base => cloudflared/dependencies.d/caddy} | 0 .../etc/s6-overlay/s6-rc.d/cloudflared/finish | 34 ++-- .../etc/s6-overlay/s6-rc.d/cloudflared/run | 12 +- .../s6-rc.d/init-cloudflared-config/up | 1 - .../rootfs/etc/s6-overlay/s6-rc.d/nginx/run | 31 ---- .../dependencies.d/base} | 0 .../prepare/run.sh} | 151 +++++++++++------- .../{init-cloudflared-config => prepare}/type | 0 .../rootfs/etc/s6-overlay/s6-rc.d/prepare/up | 1 + .../{init-cloudflared-config => caddy} | 0 .../user/contents.d/{nginx => prepare} | 0 21 files changed, 201 insertions(+), 191 deletions(-) mode change 100644 => 100755 cloudflared/rootfs/build.sh create mode 100644 cloudflared/rootfs/etc/caddy/Caddyfile.gtpl rename cloudflared/rootfs/etc/s6-overlay/s6-rc.d/{cloudflared/dependencies.d/nginx => caddy/dependencies.d/prepare} (100%) rename cloudflared/rootfs/etc/s6-overlay/s6-rc.d/{nginx => caddy}/finish (58%) create mode 100755 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run rename cloudflared/rootfs/etc/s6-overlay/s6-rc.d/{nginx => caddy}/type (100%) rename cloudflared/rootfs/etc/s6-overlay/s6-rc.d/{init-cloudflared-config/dependencies.d/base => cloudflared/dependencies.d/caddy} (100%) delete mode 100644 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/init-cloudflared-config/up delete mode 100755 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/run rename cloudflared/rootfs/etc/s6-overlay/s6-rc.d/{nginx/dependencies.d/init-cloudflared-config => prepare/dependencies.d/base} (100%) rename cloudflared/rootfs/etc/s6-overlay/{scripts/cloudflared-config.sh => s6-rc.d/prepare/run.sh} (76%) rename cloudflared/rootfs/etc/s6-overlay/s6-rc.d/{init-cloudflared-config => prepare}/type (100%) create mode 100644 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/up rename cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/{init-cloudflared-config => caddy} (100%) rename cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/{nginx => prepare} (100%) diff --git a/.github/renovate.json b/.github/renovate.json index 08cfd575..aeefc5a6 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -6,36 +6,7 @@ "labels": ["dependencies", "no-stale"], "commitMessagePrefix": "⬆️", "commitMessageTopic": "{{depName}}", - "customManagers": [ - { - "customType": "regex", - "fileMatch": ["/Dockerfile$", "/build.yaml$"], - "matchStringsStrategy": "any", - "matchStrings": [ - "ARG BUILD_FROM=(?.*?):(?.*?)\\s+", - "(aarch64|amd64|armv7):\\s[\"']?(?.*?):(?.*?)[\"']?\\s" - ], - "datasourceTemplate": "docker" - }, - { - "customType": "regex", - "fileMatch": ["/Dockerfile$"], - "matchStrings": [ - "ARG CLOUDFLARED_VERSION=[\"']?(?.+?)[\"']?\\s+" - ], - "datasourceTemplate": "github-releases", - "depNameTemplate": "cloudflare/cloudflared", - "versioningTemplate": "loose" - }, - { - "customType": "regex", - "fileMatch": ["/rootfs/build.sh$"], - "matchStrings": [ - "#\\s*renovate:\\s*datasource=(?.*?) depName=(?.*?)( versioning=(?.*?))?\\sARG .*?_version=\"(?.*)\"\\s" - ], - "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}" - } - ], + "extends": ["customManagers:dockerfileVersions"], "packageRules": [ { "groupName": "Add-on base image", diff --git a/cloudflared/Dockerfile b/cloudflared/Dockerfile index 206340ea..2b37da53 100644 --- a/cloudflared/Dockerfile +++ b/cloudflared/Dockerfile @@ -1,25 +1,23 @@ -ARG BUILD_FROM=ghcr.io/hassio-addons/base/amd64:17.2.5 -# hadolint ignore=DL3006 -FROM ${BUILD_FROM} - -# Set shell -SHELL ["/bin/bash", "-o", "pipefail", "-c"] +FROM ghcr.io/hassio-addons/base:17.2.5 # Set S6 verbosity level -ENV S6_VERBOSITY=1 +ENV S6_VERBOSITY="1" # Setup base -ARG BUILD_ARCH=amd64 +ARG BUILD_ARCH="amd64" + +# renovate: datasource=github-releases depName=caddy packageName=caddyserver/caddy +ARG CADDY_VERSION="2.10.0" +# renovate: datasource=github-releases depName=cloudflared packageName=cloudflared/cloudflare versioning=loose ARG CLOUDFLARED_VERSION="2025.5.0" # Copy root filesystem COPY rootfs / -# Run the script that installes cloudflared -RUN chmod a+x /build.sh && /build.sh "${BUILD_ARCH}" "${CLOUDFLARED_VERSION}" +# Run the script that installs caddy and cloudflared +RUN ["/build.sh"] # Build arguments -ARG BUILD_ARCH ARG BUILD_DATE ARG BUILD_DESCRIPTION ARG BUILD_NAME @@ -33,7 +31,7 @@ LABEL \ io.hass.description="${BUILD_DESCRIPTION}" \ io.hass.arch="${BUILD_ARCH}" \ io.hass.type="addon" \ - io.hass.version=${BUILD_VERSION} \ + io.hass.version="${BUILD_VERSION}" \ maintainer="Tobias Brenner " \ org.opencontainers.image.title="${BUILD_NAME}" \ org.opencontainers.image.description="${BUILD_DESCRIPTION}" \ @@ -43,6 +41,6 @@ LABEL \ org.opencontainers.image.url="https://github.com/${BUILD_REPOSITORY}" \ org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \ org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \ - org.opencontainers.image.created=${BUILD_DATE} \ - org.opencontainers.image.revision=${BUILD_REF} \ - org.opencontainers.image.version=${BUILD_VERSION} + org.opencontainers.image.created="${BUILD_DATE}" \ + org.opencontainers.image.revision="${BUILD_REF}" \ + org.opencontainers.image.version="${BUILD_VERSION}" diff --git a/cloudflared/build.yaml b/cloudflared/build.yaml index 01179913..637d8331 100644 --- a/cloudflared/build.yaml +++ b/cloudflared/build.yaml @@ -1,8 +1,4 @@ --- -build_from: - aarch64: ghcr.io/hassio-addons/base/aarch64:17.2.5 - amd64: ghcr.io/hassio-addons/base/amd64:17.2.5 - armv7: ghcr.io/hassio-addons/base/armv7:17.2.5 codenotary: base_image: codenotary@frenck.dev signer: dev@brenner.tech diff --git a/cloudflared/config.yaml b/cloudflared/config.yaml index 38d7688b..b6212174 100644 --- a/cloudflared/config.yaml +++ b/cloudflared/config.yaml @@ -15,11 +15,14 @@ arch: - armv7 map: - addon_config:rw + - ssl:rw options: external_hostname: "" additional_hosts: [] ports: 36500/tcp: null + 80/tcp: null + 443/tcp: null schema: external_hostname: str? additional_hosts: diff --git a/cloudflared/rootfs/build.sh b/cloudflared/rootfs/build.sh old mode 100644 new mode 100755 index 2bb634d5..e00d88e8 --- a/cloudflared/rootfs/build.sh +++ b/cloudflared/rootfs/build.sh @@ -5,34 +5,41 @@ # Container build of Cloudflared # ============================================================================== -# Machine architecture as first parameter -arch=$1 +set -eux + +# Adapt the architecture to the caddy specific names if needed +# see HA archs: https://developers.home-assistant.io/docs/add-ons/configuration/#:~:text=the%20add%2Don.-,arch,-list +# see Caddy archs: https://github.com/caddyserver/caddy/releases +case "${BUILD_ARCH}" in +"aarch64") + caddy_arch="arm64" + ;; +*) + caddy_arch="${BUILD_ARCH}" + ;; +esac -# Cloudflared release as second parameter -cloudflaredRelease=$2 +# Download the caddy bin +wget -q -O- "https://github.com/caddyserver/caddy/releases/download/v${CADDY_VERSION}/caddy_${CADDY_VERSION}_linux_${caddy_arch}.tar.gz" | + tar -xzf- -C /usr/bin caddy # Adapt the architecture to the cloudflared specific names if needed -# see HA Archs: https://developers.home-assistant.io/docs/add-ons/configuration/#:~:text=the%20add%2Don.-,arch,-list -# see Cloudflared Archs https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation -case $arch in - "aarch64") - arch="arm64" +# see HA archs: https://developers.home-assistant.io/docs/add-ons/configuration/#:~:text=the%20add%2Don.-,arch,-list +# see Cloudflared archs: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation +case "${BUILD_ARCH}" in +"aarch64") + cloudflared_arch="arm64" ;; - - "armv7") - arch="arm" +"armv7") + cloudflared_arch="arm" + ;; +*) + cloudflared_arch="${BUILD_ARCH}" ;; esac -# Workaround for live log streaming issue -# see https://github.com/brenner-tobias/addon-cloudflared/discussions/744 - -# renovate: datasource=repology depName=debian_12/gnupg versioning=loose -nginx_version="1.26.3-r0" -apk add --no-cache nginx="${nginx_version}" - # Download the cloudflared bin -wget -O /usr/bin/cloudflared "https://github.com/cloudflare/cloudflared/releases/download/${cloudflaredRelease}/cloudflared-linux-${arch}" +wget -q -O /usr/bin/cloudflared "https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-${cloudflared_arch}" # Make the downloaded bin executeable chmod +x /usr/bin/cloudflared @@ -41,6 +48,6 @@ chmod +x /usr/bin/cloudflared rm -rf /etc/cont-init.d # Remove s-6 legacy/deprecated (and not needed) services -rm /package/admin/s6-overlay/etc/s6-rc/sources/base/contents.d/legacy-cont-init -rm /package/admin/s6-overlay/etc/s6-rc/sources/base/contents.d/fix-attrs -rm /package/admin/s6-overlay/etc/s6-rc/sources/top/contents.d/legacy-services +rm -f /package/admin/s6-overlay/etc/s6-rc/sources/base/contents.d/legacy-cont-init +rm -f /package/admin/s6-overlay/etc/s6-rc/sources/base/contents.d/fix-attrs +rm -f /package/admin/s6-overlay/etc/s6-rc/sources/top/contents.d/legacy-services diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl new file mode 100644 index 00000000..32ddffaa --- /dev/null +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -0,0 +1,16 @@ +{{ .ha_external_hostname }}.internal { + tls internal + reverse_proxy http://homeassistant:{{ .ha_port }} +} +{{ .ha_external_hostname }} { + reverse_proxy http://homeassistant:{{ .ha_port }} +} +{{ range $i, $e := .additional_hosts }} +{{ $e.hostname }}.internal { + tls internal + reverse_proxy {{ $e.service }} +} +{{ $e.hostname }} { + reverse_proxy {{ $e.service }} +} +{{ end }} diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/dependencies.d/nginx b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/dependencies.d/prepare similarity index 100% rename from cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/dependencies.d/nginx rename to cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/dependencies.d/prepare diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish similarity index 58% rename from cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish rename to cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish index b547192e..f75d3a82 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/finish +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish @@ -1,14 +1,14 @@ #!/command/with-contenv bashio +# shellcheck shell=bash # ============================================================================== # Home Assistant Add-on: Cloudflared -# Take down the S6 supervision tree when NGINX fails +# Take down the S6 supervision tree when the Caddy fails # ============================================================================== - -# shellcheck disable=SC2155 -readonly exit_code_container=$( /run/s6-linux-init-container-results/exitcode + echo $((128 + exit_code_signal)) >/run/s6-linux-init-container-results/exitcode + fi + if [[ "${exit_code_signal}" -eq 15 ]]; then + exec /run/s6/basedir/bin/halt fi - [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt elif [[ "${exit_code_service}" -ne 0 ]]; then if [[ "${exit_code_container}" -eq 0 ]]; then - echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode + echo "${exit_code_service}" >/run/s6-linux-init-container-results/exitcode fi exec /run/s6/basedir/bin/halt -fi \ No newline at end of file +fi diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run new file mode 100755 index 00000000..09c0bac2 --- /dev/null +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run @@ -0,0 +1,7 @@ +#!/command/with-contenv bashio +# shellcheck shell=bash + +bashio::log.info "Starting Caddy..." +export XDG_DATA_HOME=/data/caddy-data +export XDG_CONFIG_HOME=/data/caddy-config +exec caddy run --config /etc/caddy/Caddyfile diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/type b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/type similarity index 100% rename from cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/type rename to cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/type diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/init-cloudflared-config/dependencies.d/base b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/dependencies.d/caddy similarity index 100% rename from cloudflared/rootfs/etc/s6-overlay/s6-rc.d/init-cloudflared-config/dependencies.d/base rename to cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/dependencies.d/caddy diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish index 52b3308b..b69d9d66 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish @@ -1,19 +1,29 @@ #!/command/with-contenv bashio +# shellcheck shell=bash # ============================================================================== # Home Assistant Add-on: Cloudflared -# Take down the S6 supervision tree when Cloudflared fails +# Take down the S6 supervision tree when the cloudflared fails # ============================================================================== +readonly exit_code_service="${1}" +readonly exit_code_signal="${2}" +exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode) +readonly exit_code_container +readonly service="cloudflared" -if test "$1" -eq 256 ; then - e=$((128 + $2)) -else - e="$1" -fi -echo "$e" > /run/s6-linux-init-container-results/exitcode +bashio::log.info \ + "Service ${service} exited with code ${exit_code_service}" \ + "(by signal ${exit_code_signal})" -if [[ "${1}" -ne 0 ]] && [[ "${1}" -ne 256 ]]; then - bashio::log.warning "cloudflared crashed, halting add-on" - /run/s6/basedir/bin/halt +if [[ "${exit_code_service}" -eq 256 ]]; then + if [[ "${exit_code_container}" -eq 0 ]]; then + echo $((128 + exit_code_signal)) >/run/s6-linux-init-container-results/exitcode + fi + if [[ "${exit_code_signal}" -eq 15 ]]; then + exec /run/s6/basedir/bin/halt + fi +elif [[ "${exit_code_service}" -ne 0 ]]; then + if [[ "${exit_code_container}" -eq 0 ]]; then + echo "${exit_code_service}" >/run/s6-linux-init-container-results/exitcode + fi + exec /run/s6/basedir/bin/halt fi - -bashio::log.info "cloudflared stopped, restarting..." \ No newline at end of file diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/run b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/run index b528d9ab..f56339eb 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/run +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/run @@ -1,4 +1,5 @@ #!/command/with-contenv bashio +# shellcheck shell=bash # ============================================================================== # Home Assistant Add-on: Cloudflared # Runs the Cloudflare Tunnel for Home Assistant @@ -7,19 +8,18 @@ declare config_file="/tmp/config.json" declare certificate="/data/cert.pem" declare -a options - # Set common cloudflared tunnel options options+=(--no-autoupdate) options+=(--metrics="0.0.0.0:36500") # Check for post_quantum option -if bashio::config.true 'post_quantum' ; then +if bashio::config.true 'post_quantum'; then bashio::log.trace "bashio::config.true 'post_quantum'" options+=(--post-quantum) fi # Check for additional run parameters -if bashio::config.has_value 'run_parameters' ; then +if bashio::config.has_value 'run_parameters'; then bashio::log.trace "bashio::config.has_value 'run_parameters'" for run_parameter in $(bashio::config 'run_parameters'); do bashio::log.trace "Adding run_parameter: ${run_parameter}" @@ -28,7 +28,7 @@ if bashio::config.has_value 'run_parameters' ; then fi # Check if we run local or remote managed tunnel and set related options -if bashio::config.has_value 'tunnel_token' ; then +if bashio::config.has_value 'tunnel_token'; then bashio::log.trace "bashio::config.has_value 'tunnel_token'" options+=(run --token="$(bashio::config 'tunnel_token')") else @@ -39,6 +39,6 @@ else fi bashio::log.info "Connecting Cloudflare Tunnel..." -bashio::log.debug "cloudflared tunnel ${options[@]}" +bashio::log.debug "cloudflared tunnel ${options[*]}" exec cloudflared \ - tunnel "${options[@]}" + tunnel "${options[@]}" diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/init-cloudflared-config/up b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/init-cloudflared-config/up deleted file mode 100644 index ba513dd4..00000000 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/init-cloudflared-config/up +++ /dev/null @@ -1 +0,0 @@ -/bin/bash -c /etc/s6-overlay/scripts/cloudflared-config.sh \ No newline at end of file diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/run b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/run deleted file mode 100755 index 37e8c66b..00000000 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/run +++ /dev/null @@ -1,31 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck disable=SC2207 -# ============================================================================== -# Home Assistant Add-on: Cloudflared -# -# Configures the nginx service as workaround to get live streaming logs working -# see https://github.com/brenner-tobias/addon-cloudflared/discussions/744 -# ============================================================================== -# set up and run nginx -# ============================================================================== - -set -e - -bashio::log.debug "Merging options & variables for template" -# shellcheck disable=SC2046 -JSON_CONF=$(jq -n \ - --arg port "$(bashio::core.port)" \ - --arg ssl "$(bashio::core.ssl)" \ - '{port: $port, ssl: ($ssl | fromjson)}') -bashio::log.debug "Generating nginx.conf from template in /etc/nginx/servers/homeassistant.conf" -bashio::log.debug "JSON_CONF: ${JSON_CONF}" -# shellcheck disable=SC2086 -echo $JSON_CONF | tempio \ - -template /etc/nginx/template/homeassistant.gtpl \ - -out /etc/nginx/servers/homeassistant.conf -bashio::log.debug "Generated nginx.conf:" -bashio::log.debug "$(cat /etc/nginx/servers/homeassistant.conf)" - -# start server -bashio::log.info "Running nginx..." -exec nginx -c /etc/nginx/nginx.conf < /dev/null \ No newline at end of file diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/init-cloudflared-config b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/dependencies.d/base similarity index 100% rename from cloudflared/rootfs/etc/s6-overlay/s6-rc.d/nginx/dependencies.d/init-cloudflared-config rename to cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/dependencies.d/base diff --git a/cloudflared/rootfs/etc/s6-overlay/scripts/cloudflared-config.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh similarity index 76% rename from cloudflared/rootfs/etc/s6-overlay/scripts/cloudflared-config.sh rename to cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 03d14b6f..553d75ee 100755 --- a/cloudflared/rootfs/etc/s6-overlay/scripts/cloudflared-config.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -1,5 +1,5 @@ #!/command/with-contenv bashio -# shellcheck disable=SC2207 +# shellcheck shell=bash # ============================================================================== # Home Assistant Add-on: Cloudflared # @@ -17,21 +17,24 @@ checkConfig() { local validHostnameRegex="^(([a-z0-9äöüß]|[a-z0-9äöüß][a-z0-9äöüß\-]*[a-z0-9äöüß])\.)*([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$" # Check for minimum configuration options - if bashio::config.is_empty 'external_hostname' && bashio::config.is_empty 'additional_hosts' && - bashio::config.is_empty 'catch_all_service' && bashio::config.is_empty 'nginx_proxy_manager'; + if + bashio::config.is_empty 'external_hostname' && + bashio::config.is_empty 'additional_hosts' && + bashio::config.is_empty 'catch_all_service' && + bashio::config.is_empty 'nginx_proxy_manager' then bashio::exit.nok "Cannot run without tunnel_token, external_hostname, additional_hosts, catch_all_service or nginx_proxy_manager. Please set at least one of these add-on options." fi # Check if 'external_hostname' includes a valid hostname - if bashio::config.has_value 'external_hostname' ; then - if ! [[ $(bashio::config 'external_hostname') =~ ${validHostnameRegex} ]] ; then + if bashio::config.has_value 'external_hostname'; then + if ! [[ $(bashio::config 'external_hostname') =~ ${validHostnameRegex} ]]; then bashio::exit.nok "'$(bashio::config 'external_hostname')' is not a valid hostname. Please make sure not to include the protocol (e.g. 'https://') nor the port (e.g. ':8123') and only use lowercase characters in the 'external_hostname'." fi fi # Check if all defined 'additional_hosts' have non-empty strings as hostname and service - if bashio::config.has_value 'additional_hosts' ; then + if bashio::config.has_value 'additional_hosts'; then local hostname local service for additional_host in $(bashio::jq "/data/options.json" ".additional_hosts[]"); do @@ -41,26 +44,26 @@ checkConfig() { if bashio::var.is_empty "${hostname}" && bashio::var.is_empty "${service}"; then bashio::exit.nok "'hostname' and 'service' in 'additional_hosts' are empty, please enter a valid String" fi - if bashio::var.is_empty "${hostname}" ; then + if bashio::var.is_empty "${hostname}"; then bashio::exit.nok "'hostname' in 'additional_hosts' for service ${service} is empty, please enter a valid String" fi # Check if hostname of 'additional_host' includes a valid hostname - if ! [[ ${hostname} =~ ${validHostnameRegex} ]] ; then + if ! [[ ${hostname} =~ ${validHostnameRegex} ]]; then bashio::exit.nok "'${hostname}' in 'additional_hosts' is not a valid hostname. Please make sure not to include the protocol (e.g. 'https://') nor the port (e.g. ':8123') and only use lowercase characters in the 'hostname'." fi - if bashio::var.is_empty "${service}" ; then + if bashio::var.is_empty "${service}"; then bashio::exit.nok "'service' in 'additional_hosts' for hostname ${hostname} is empty, please enter a valid String" fi done fi # Check if 'catch_all_service' is included in config with an empty String - if bashio::config.exists 'catch_all_service' && bashio::config.is_empty 'catch_all_service' ; then + if bashio::config.exists 'catch_all_service' && bashio::config.is_empty 'catch_all_service'; then bashio::exit.nok "'catch_all_service' is defined as an empty String. Please remove 'catch_all_service' from the configuration or enter a valid String" fi # Check if 'catch_all_service' and 'nginx_proxy_manager' are both included in config. - if bashio::config.has_value 'catch_all_service' && bashio::config.true 'nginx_proxy_manager' ; then + if bashio::config.has_value 'catch_all_service' && bashio::config.true 'nginx_proxy_manager'; then bashio::exit.nok "The config includes 'nginx_proxy_manager' and 'catch_all_service'. Please delete one of them since they are mutually exclusive" fi } @@ -73,40 +76,40 @@ checkConnectivity() { # Check for region1 TCP bashio::log.debug "Checking region1.v2.argotunnel.com TCP port 7844" - if ! nc -z -w 1 region1.v2.argotunnel.com 7844 &> /dev/null ; then + if ! nc -z -w 1 region1.v2.argotunnel.com 7844 &>/dev/null; then bashio::log.warning "region1.v2.argotunnel.com TCP port 7844 not reachable" pass_test=false fi # Check for region1 UDP bashio::log.debug "Checking region1.v2.argotunnel.com UDP port 7844" - if ! nc -z -u -w 1 region1.v2.argotunnel.com 7844 &> /dev/null ; then + if ! nc -z -u -w 1 region1.v2.argotunnel.com 7844 &>/dev/null; then bashio::log.warning "region1.v2.argotunnel.com UDP port 7844 not reachable" pass_test=false fi # Check for region2 TCP bashio::log.debug "Checking region2.v2.argotunnel.com TCP port 7844" - if ! nc -z -w 1 region2.v2.argotunnel.com 7844 &> /dev/null ; then + if ! nc -z -w 1 region2.v2.argotunnel.com 7844 &>/dev/null; then bashio::log.warning "region2.v2.argotunnel.com TCP port 7844 not reachable" pass_test=false fi # Check for region2 UDP bashio::log.debug "Checking region2.v2.argotunnel.com UDP port 7844" - if ! nc -z -u -w 1 region2.v2.argotunnel.com 7844 &> /dev/null ; then + if ! nc -z -u -w 1 region2.v2.argotunnel.com 7844 &>/dev/null; then bashio::log.warning "region2.v2.argotunnel.com UDP port 7844 not reachable" pass_test=false fi # Check for API TCP bashio::log.debug "Checking api.cloudflare.com TCP port 443" - if ! nc -z -w 1 api.cloudflare.com 443 &> /dev/null ; then + if ! nc -z -w 1 api.cloudflare.com 443 &>/dev/null; then bashio::log.warning "api.cloudflare.com TCP port 443 not reachable" pass_test=false fi - if bashio::var.false ${pass_test} ; then + if bashio::var.false ${pass_test}; then bashio::log.warning "Some necessary services may not be reachable from your host." bashio::log.warning "Please review lines above and check your firewall/router settings." fi @@ -119,7 +122,7 @@ checkConnectivity() { hasCertificate() { bashio::log.trace "${FUNCNAME[0]}" bashio::log.info "Checking for existing certificate..." - if bashio::fs.file_exists "${data_path}/cert.pem" ; then + if bashio::fs.file_exists "${data_path}/cert.pem"; then bashio::log.info "Existing certificate found" return "${__BASHIO_EXIT_OK}" fi @@ -154,7 +157,7 @@ hasTunnel() { bashio::log.info "Checking for existing tunnel..." # Check if tunnel file(s) exist - if ! bashio::fs.file_exists "${data_path}/tunnel.json" ; then + if ! bashio::fs.file_exists "${data_path}/tunnel.json"; then bashio::log.notice "No tunnel file found" return "${__BASHIO_EXIT_NOK}" fi @@ -191,8 +194,8 @@ hasTunnel() { createTunnel() { bashio::log.trace "${FUNCNAME[0]}" bashio::log.info "Creating new tunnel..." - cloudflared --origincert="${data_path}/cert.pem" --cred-file="${data_path}/tunnel.json" tunnel --loglevel "${CLOUDFLARED_LOG}" create "${tunnel_name}" \ - || bashio::exit.nok "Failed to create tunnel. + cloudflared --origincert="${data_path}/cert.pem" --cred-file="${data_path}/tunnel.json" tunnel --loglevel "${CLOUDFLARED_LOG}" create "${tunnel_name}" || + bashio::exit.nok "Failed to create tunnel. Please check the Cloudflare Zero Trust Dashboard for an existing tunnel with the name ${tunnel_name} and delete it: Visit https://one.dash.cloudflare.com, then click on Access / Tunnels" @@ -215,50 +218,55 @@ createConfig() { config=$(bashio::jq "${config}" ".\"credentials-file\" += \"${data_path}/tunnel.json\"") bashio::log.debug "Checking if SSL is used..." - if bashio::var.true "$(bashio::core.ssl)" ; then + if bashio::var.true "$(bashio::core.ssl)"; then ha_service_protocol="https" else ha_service_protocol="http" fi bashio::log.debug "ha_service_protocol: ${ha_service_protocol}" - if bashio::var.is_empty "${ha_service_protocol}" ; then + if bashio::var.is_empty "${ha_service_protocol}"; then bashio::exit.nok "Error checking if SSL is enabled" fi # Add Service for Home Assistant if 'external_hostname' is set - if bashio::config.has_value 'external_hostname' ; then - if ! bashio::config.has_value 'use_builtin_proxy' || bashio::config.true 'use_builtin_proxy' ; then - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"http://localhost:8321\"}]") + if bashio::config.has_value 'external_hostname'; then + if ! bashio::config.has_value 'use_builtin_proxy' || bashio::config.true 'use_builtin_proxy'; then + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"https://${external_hostname}.internal\"}]") else config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_service_protocol}://homeassistant:$(bashio::core.port)\"}]") fi fi # Check for configured additional hosts and add them if existing - if bashio::config.has_value 'additional_hosts' ; then + if bashio::config.has_value 'additional_hosts'; then # Loop additional_hosts to create json config while read -r additional_host; do # Check for originRequest configuration option: disableChunkedEncoding disableChunkedEncoding=$(bashio::jq "${additional_host}" ". | select(.disableChunkedEncoding != null) | .disableChunkedEncoding ") - if ! [[ ${disableChunkedEncoding} == "" ]] ; then + if ! [[ ${disableChunkedEncoding} == "" ]]; then additional_host=$(bashio::jq "${additional_host}" "del(.disableChunkedEncoding)") additional_host=$(bashio::jq "${additional_host}" ".originRequest += {\"disableChunkedEncoding\": ${disableChunkedEncoding}}") fi + + if ! bashio::config.has_value 'use_builtin_proxy' || bashio::config.true 'use_builtin_proxy'; then + additional_host=$(bashio::jq "${additional_host}" '.service = "https://\(.hostname).internal"') + fi + # Add additional_host config to ingress config config=$(bashio::jq "${config}" ".ingress[.ingress | length ] |= . + ${additional_host}") - done <<< "$(jq -c '.additional_hosts[]' /data/options.json )" + done <<<"$(jq -c '.additional_hosts[]' /data/options.json)" fi # Check if NGINX Proxy Manager is used to finalize configuration - if bashio::config.true 'nginx_proxy_manager' ; then + if bashio::config.true 'nginx_proxy_manager'; then bashio::log.warning "Runing with Nginxproxymanager support, make sure the add-on is installed and running." config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://a0d7b954-nginxproxymanager:80\"}]") else # Check if catch all service is defined - if bashio::config.has_value 'catch_all_service' ; then + if bashio::config.has_value 'catch_all_service'; then bashio::log.info "Runing with Catch all Service" # Setting catch all service to defined URL @@ -273,13 +281,13 @@ createConfig() { config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"noTLSVerify\": true}") # Write content of config variable to config file for cloudflared - bashio::jq "${config}" "." > "${default_config}" + bashio::jq "${config}" "." >"${default_config}" # Validate config using cloudflared bashio::log.info "Validating config file..." bashio::log.debug "Validating created config file: $(bashio::jq "${default_config}" ".")" - cloudflared tunnel --config="${default_config}" --loglevel "${CLOUDFLARED_LOG}" ingress validate \ - || bashio::exit.nok "Validation of Config failed, please check the logs above." + cloudflared tunnel --config="${default_config}" --loglevel "${CLOUDFLARED_LOG}" ingress validate || + bashio::exit.nok "Validation of Config failed, please check the logs above." bashio::log.debug "Sucessfully created config file: $(bashio::jq "${default_config}" ".")" } @@ -291,21 +299,21 @@ createDNS() { bashio::log.trace "${FUNCNAME[0]}" # Create DNS entry for external hostname of Home Assistant if 'external_hostname' is set - if bashio::config.has_value 'external_hostname' ; then + if bashio::config.has_value 'external_hostname'; then bashio::log.info "Creating DNS entry ${external_hostname}..." - cloudflared --origincert="${data_path}/cert.pem" tunnel --loglevel "${CLOUDFLARED_LOG}" route dns -f "${tunnel_uuid}" "${external_hostname}" \ - || bashio::exit.nok "Failed to create DNS entry ${external_hostname}." + cloudflared --origincert="${data_path}/cert.pem" tunnel --loglevel "${CLOUDFLARED_LOG}" route dns -f "${tunnel_uuid}" "${external_hostname}" || + bashio::exit.nok "Failed to create DNS entry ${external_hostname}." fi # Check for configured additional hosts and create DNS entries for them if existing - if bashio::config.has_value 'additional_hosts' ; then + if bashio::config.has_value 'additional_hosts'; then for host in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do bashio::log.info "Creating DNS entry ${host}..." - if bashio::var.is_empty "${host}" ; then + if bashio::var.is_empty "${host}"; then bashio::exit.nok "'hostname' in 'additional_hosts' is empty, please enter a valid String" fi - cloudflared --origincert="${data_path}/cert.pem" tunnel --loglevel "${CLOUDFLARED_LOG}" route dns -f "${tunnel_uuid}" "${host}" \ - || bashio::exit.nok "Failed to create DNS entry ${host}." + cloudflared --origincert="${data_path}/cert.pem" tunnel --loglevel "${CLOUDFLARED_LOG}" route dns -f "${tunnel_uuid}" "${host}" || + bashio::exit.nok "Failed to create DNS entry ${host}." done fi } @@ -315,22 +323,22 @@ createDNS() { # ------------------------------------------------------------------------------ setCloudflaredLogLevel() { -# Set cloudflared log to "info" as default -CLOUDFLARED_LOG="info" - -# Check if user wishes to change log severity -if bashio::config.has_value 'run_parameters' ; then - bashio::log.trace "bashio::config.has_value 'run_parameters'" - for run_parameter in $(bashio::config 'run_parameters'); do - bashio::log.trace "Checking run_parameter: ${run_parameter}" - if [[ $run_parameter == --loglevel=* ]]; then - CLOUDFLARED_LOG=${run_parameter#*=} - bashio::log.trace "Setting CLOUDFLARED_LOG to: ${run_parameter#*=}" - fi - done -fi + # Set cloudflared log to "info" as default + CLOUDFLARED_LOG="info" + + # Check if user wishes to change log severity + if bashio::config.has_value 'run_parameters'; then + bashio::log.trace "bashio::config.has_value 'run_parameters'" + for run_parameter in $(bashio::config 'run_parameters'); do + bashio::log.trace "Checking run_parameter: ${run_parameter}" + if [[ $run_parameter == --loglevel=* ]]; then + CLOUDFLARED_LOG=${run_parameter#*=} + bashio::log.trace "Setting CLOUDFLARED_LOG to: ${run_parameter#*=}" + fi + done + fi -bashio::log.debug "Cloudflared log level set to \"${CLOUDFLARED_LOG}\"" + bashio::log.debug "Cloudflared log level set to \"${CLOUDFLARED_LOG}\"" } @@ -349,7 +357,7 @@ main() { setCloudflaredLogLevel # Run connectivity checks if debug mode activated - if bashio::debug ; then + if bashio::debug; then bashio::log.debug "Checking connectivity to Cloudflare" checkConnectivity fi @@ -363,17 +371,17 @@ main() { checkConfig - if bashio::config.has_value 'tunnel_name' ; then + if bashio::config.has_value 'tunnel_name'; then tunnel_name="$(bashio::config 'tunnel_name')" fi external_hostname="$(bashio::config 'external_hostname')" - if ! hasCertificate ; then + if ! hasCertificate; then createCertificate fi - if ! hasTunnel ; then + if ! hasTunnel; then createTunnel fi @@ -381,6 +389,29 @@ main() { createDNS + bashio::log.info "Configuring Caddy..." + bashio::log.debug "Generating Caddyfile from template in /etc/caddy/Caddyfile" + json=$( + jq -n \ + --arg ha_external_hostname "${external_hostname}" \ + --arg ha_port "$(bashio::core.port)" \ + --argjson ha_ssl "$(bashio::core.ssl)" \ + --argjson additional_hosts "$(jq -c '.additional_hosts' /data/options.json)" \ + '{ha_external_hostname: $ha_external_hostname, ha_port: $ha_port, ha_ssl: $ha_ssl, additional_hosts: $additional_hosts}' + ) + bashio::log.debug "JSON: ${json}" + echo "${json}" | tempio -template /etc/caddy/Caddyfile.gtpl -out /etc/caddy/Caddyfile + bashio::log.debug "Generated Caddyfile:" + bashio::log.debug "$(cat /etc/caddy/Caddyfile)" + + # add entries to /etc/hosts + echo "127.0.0.1 ${external_hostname}.internal" >>/etc/hosts + if bashio::config.has_value 'additional_hosts'; then + for host in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do + echo "127.0.0.1 ${host}.internal" >>/etc/hosts + done + fi + bashio::log.info "Finished setting up the Cloudflare Tunnel" } main "$@" diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/init-cloudflared-config/type b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/type similarity index 100% rename from cloudflared/rootfs/etc/s6-overlay/s6-rc.d/init-cloudflared-config/type rename to cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/type diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/up b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/up new file mode 100644 index 00000000..9b67615b --- /dev/null +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/up @@ -0,0 +1 @@ +/etc/s6-overlay/s6-rc.d/prepare/run.sh \ No newline at end of file diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/init-cloudflared-config b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/caddy similarity index 100% rename from cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/init-cloudflared-config rename to cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/caddy diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/nginx b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/prepare similarity index 100% rename from cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/nginx rename to cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/prepare From c1f43e0c3686f9a870db0c13c04a2fb259ded269 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Fri, 23 May 2025 15:21:55 -0300 Subject: [PATCH 02/55] Refactor some stuff --- cloudflared/config.yaml | 4 + cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 20 ++-- .../rootfs/etc/nginx/includes/mime.types | 96 ------------------- .../etc/nginx/includes/proxy_params.conf | 16 ---- .../etc/nginx/includes/server_params.conf | 10 -- cloudflared/rootfs/etc/nginx/nginx.conf | 43 --------- cloudflared/rootfs/etc/nginx/servers/.gitkeep | 0 .../etc/nginx/template/homeassistant.gtpl | 33 ------- .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 10 +- 9 files changed, 19 insertions(+), 213 deletions(-) delete mode 100644 cloudflared/rootfs/etc/nginx/includes/mime.types delete mode 100644 cloudflared/rootfs/etc/nginx/includes/proxy_params.conf delete mode 100644 cloudflared/rootfs/etc/nginx/includes/server_params.conf delete mode 100644 cloudflared/rootfs/etc/nginx/nginx.conf delete mode 100644 cloudflared/rootfs/etc/nginx/servers/.gitkeep delete mode 100644 cloudflared/rootfs/etc/nginx/template/homeassistant.gtpl diff --git a/cloudflared/config.yaml b/cloudflared/config.yaml index b6212174..58ac466f 100644 --- a/cloudflared/config.yaml +++ b/cloudflared/config.yaml @@ -23,12 +23,16 @@ ports: 36500/tcp: null 80/tcp: null 443/tcp: null + 443/udp: null +privileged: + - NET_ADMIN schema: external_hostname: str? additional_hosts: - hostname: str service: str disableChunkedEncoding: bool? + internalOnly: bool? tunnel_name: str? catch_all_service: str? nginx_proxy_manager: bool? diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 32ddffaa..25209e38 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -1,16 +1,14 @@ -{{ .ha_external_hostname }}.internal { - tls internal - reverse_proxy http://homeassistant:{{ .ha_port }} -} {{ .ha_external_hostname }} { - reverse_proxy http://homeassistant:{{ .ha_port }} -} -{{ range $i, $e := .additional_hosts }} -{{ $e.hostname }}.internal { - tls internal - reverse_proxy {{ $e.service }} + reverse_proxy http://homeassistant:{{ .ha_port }} } +{{ range $i, $e := .additional_hosts -}} {{ $e.hostname }} { - reverse_proxy {{ $e.service }} + {{ if $e.internalOnly -}} + @localhost remote_ip 127.0.0.1 + handle @localhost { + respond "This service can only be accessed from the local network." 403 + } + {{- end }} + reverse_proxy {{ $e.service }} } {{ end }} diff --git a/cloudflared/rootfs/etc/nginx/includes/mime.types b/cloudflared/rootfs/etc/nginx/includes/mime.types deleted file mode 100644 index c2302120..00000000 --- a/cloudflared/rootfs/etc/nginx/includes/mime.types +++ /dev/null @@ -1,96 +0,0 @@ -types { - text/html html htm shtml; - text/css css; - text/xml xml; - image/gif gif; - image/jpeg jpeg jpg; - application/javascript js; - application/atom+xml atom; - application/rss+xml rss; - - text/mathml mml; - text/plain txt; - text/vnd.sun.j2me.app-descriptor jad; - text/vnd.wap.wml wml; - text/x-component htc; - - image/png png; - image/svg+xml svg svgz; - image/tiff tif tiff; - image/vnd.wap.wbmp wbmp; - image/webp webp; - image/x-icon ico; - image/x-jng jng; - image/x-ms-bmp bmp; - - font/woff woff; - font/woff2 woff2; - - application/java-archive jar war ear; - application/json json; - application/mac-binhex40 hqx; - application/msword doc; - application/pdf pdf; - application/postscript ps eps ai; - application/rtf rtf; - application/vnd.apple.mpegurl m3u8; - application/vnd.google-earth.kml+xml kml; - application/vnd.google-earth.kmz kmz; - application/vnd.ms-excel xls; - application/vnd.ms-fontobject eot; - application/vnd.ms-powerpoint ppt; - application/vnd.oasis.opendocument.graphics odg; - application/vnd.oasis.opendocument.presentation odp; - application/vnd.oasis.opendocument.spreadsheet ods; - application/vnd.oasis.opendocument.text odt; - application/vnd.openxmlformats-officedocument.presentationml.presentation - pptx; - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - xlsx; - application/vnd.openxmlformats-officedocument.wordprocessingml.document - docx; - application/vnd.wap.wmlc wmlc; - application/x-7z-compressed 7z; - application/x-cocoa cco; - application/x-java-archive-diff jardiff; - application/x-java-jnlp-file jnlp; - application/x-makeself run; - application/x-perl pl pm; - application/x-pilot prc pdb; - application/x-rar-compressed rar; - application/x-redhat-package-manager rpm; - application/x-sea sea; - application/x-shockwave-flash swf; - application/x-stuffit sit; - application/x-tcl tcl tk; - application/x-x509-ca-cert der pem crt; - application/x-xpinstall xpi; - application/xhtml+xml xhtml; - application/xspf+xml xspf; - application/zip zip; - - application/octet-stream bin exe dll; - application/octet-stream deb; - application/octet-stream dmg; - application/octet-stream iso img; - application/octet-stream msi msp msm; - - audio/midi mid midi kar; - audio/mpeg mp3; - audio/ogg ogg; - audio/x-m4a m4a; - audio/x-realaudio ra; - - video/3gpp 3gpp 3gp; - video/mp2t ts; - video/mp4 mp4; - video/mpeg mpeg mpg; - video/quicktime mov; - video/webm webm; - video/x-flv flv; - video/x-m4v m4v; - video/x-mng mng; - video/x-ms-asf asx asf; - video/x-ms-wmv wmv; - video/x-msvideo avi; -} \ No newline at end of file diff --git a/cloudflared/rootfs/etc/nginx/includes/proxy_params.conf b/cloudflared/rootfs/etc/nginx/includes/proxy_params.conf deleted file mode 100644 index 969ca6f5..00000000 --- a/cloudflared/rootfs/etc/nginx/includes/proxy_params.conf +++ /dev/null @@ -1,16 +0,0 @@ -proxy_http_version 1.1; -proxy_ignore_client_abort off; -proxy_read_timeout 86400s; -proxy_redirect off; -proxy_send_timeout 86400s; -proxy_max_temp_file_size 0; -proxy_buffering off; - -proxy_set_header Accept-Encoding ""; -proxy_set_header Connection $connection_upgrade; -proxy_set_header Host $http_host; -proxy_set_header Upgrade $http_upgrade; -proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -proxy_set_header X-Forwarded-Proto $scheme; -proxy_set_header X-NginX-Proxy true; -proxy_set_header X-Real-IP $remote_addr; \ No newline at end of file diff --git a/cloudflared/rootfs/etc/nginx/includes/server_params.conf b/cloudflared/rootfs/etc/nginx/includes/server_params.conf deleted file mode 100644 index b87656d1..00000000 --- a/cloudflared/rootfs/etc/nginx/includes/server_params.conf +++ /dev/null @@ -1,10 +0,0 @@ -root /dev/null; -server_name $hostname; - -client_max_body_size 512m; - -add_header X-Content-Type-Options nosniff; -add_header X-XSS-Protection "1; mode=block"; -add_header X-Robots-Tag none; -add_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; -expires off; \ No newline at end of file diff --git a/cloudflared/rootfs/etc/nginx/nginx.conf b/cloudflared/rootfs/etc/nginx/nginx.conf deleted file mode 100644 index 4e062ee1..00000000 --- a/cloudflared/rootfs/etc/nginx/nginx.conf +++ /dev/null @@ -1,43 +0,0 @@ -# Run nginx in foreground. -daemon off; - -# This is run inside Docker. -user root; - -# Pid storage location. -pid /var/run/nginx.pid; - -# Set number of worker processes. -worker_processes 1; - -# Enables the use of JIT for regular expressions to speed-up their processing. -pcre_jit on; - -# Write error log to the add-on log. -error_log /proc/1/fd/1 warn; - -# Max num of simultaneous connections by a worker process. -events { - worker_connections 512; -} - -http { - include /etc/nginx/includes/mime.types; - - access_log off; - client_max_body_size 4G; - default_type application/octet-stream; - gzip on; - keepalive_timeout 65; - sendfile on; - server_tokens off; - tcp_nodelay on; - tcp_nopush on; - - map $http_upgrade $connection_upgrade { - default upgrade; - '' close; - } - - include /etc/nginx/servers/*.conf; -} \ No newline at end of file diff --git a/cloudflared/rootfs/etc/nginx/servers/.gitkeep b/cloudflared/rootfs/etc/nginx/servers/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/cloudflared/rootfs/etc/nginx/template/homeassistant.gtpl b/cloudflared/rootfs/etc/nginx/template/homeassistant.gtpl deleted file mode 100644 index dc2d7b4c..00000000 --- a/cloudflared/rootfs/etc/nginx/template/homeassistant.gtpl +++ /dev/null @@ -1,33 +0,0 @@ -server { - - listen 8321; - - include /etc/nginx/includes/server_params.conf; - include /etc/nginx/includes/proxy_params.conf; - - - - location / { - {{- if not .ssl }} - proxy_pass http://homeassistant:{{ .port }}; - {{- else }} - proxy_pass https://homeassistant:{{ .port }}; - proxy_ssl_verify off; - {{- end }} - # proxy_set_header X-Forwarded-Host $http_host; - } - - location ~ /api/hassio/.*/logs.*/follow { - {{- if not .ssl }} - proxy_pass http://homeassistant:{{ .port }}; - {{- else }} - proxy_pass https://homeassistant:{{ .port }}; - proxy_ssl_verify off; - {{- end }} - # proxy_set_header X-Forwarded-Host $http_host; - proxy_read_timeout 1d; - proxy_cache off; - proxy_hide_header Content-Type; - add_header Content-Type "text/event-stream"; - } -} diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 553d75ee..4605a913 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -232,7 +232,7 @@ createConfig() { # Add Service for Home Assistant if 'external_hostname' is set if bashio::config.has_value 'external_hostname'; then if ! bashio::config.has_value 'use_builtin_proxy' || bashio::config.true 'use_builtin_proxy'; then - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"https://${external_hostname}.internal\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"https://${external_hostname}\"}]") else config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_service_protocol}://homeassistant:$(bashio::core.port)\"}]") fi @@ -250,9 +250,11 @@ createConfig() { fi if ! bashio::config.has_value 'use_builtin_proxy' || bashio::config.true 'use_builtin_proxy'; then - additional_host=$(bashio::jq "${additional_host}" '.service = "https://\(.hostname).internal"') + additional_host=$(bashio::jq "${additional_host}" '.service = "https://\(.hostname)"') fi + additional_host=$(bashio::jq "${additional_host}" "del(.internalOnly)") + # Add additional_host config to ingress config config=$(bashio::jq "${config}" ".ingress[.ingress | length ] |= . + ${additional_host}") done <<<"$(jq -c '.additional_hosts[]' /data/options.json)" @@ -405,10 +407,10 @@ main() { bashio::log.debug "$(cat /etc/caddy/Caddyfile)" # add entries to /etc/hosts - echo "127.0.0.1 ${external_hostname}.internal" >>/etc/hosts + echo "127.0.0.1 ${external_hostname}" | tee -a /etc/hosts if bashio::config.has_value 'additional_hosts'; then for host in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do - echo "127.0.0.1 ${host}.internal" >>/etc/hosts + echo "127.0.0.1 ${host}" | tee -a /etc/hosts done fi From 7b2a15c0791b0a2d33e17ecdfe71bb537a867b6f Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Fri, 23 May 2025 16:21:42 -0300 Subject: [PATCH 03/55] Handle auto https --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 11 ++++-- .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 35 +++++++++++++------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 25209e38..821fd6fd 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -1,3 +1,8 @@ +{{ if not .auto_https -}} +{ + local_certs +} +{{ end -}} {{ .ha_external_hostname }} { reverse_proxy http://homeassistant:{{ .ha_port }} } @@ -6,9 +11,9 @@ {{ if $e.internalOnly -}} @localhost remote_ip 127.0.0.1 handle @localhost { - respond "This service can only be accessed from the local network." 403 + respond "This service can only be accessed from local network." 403 } - {{- end }} + {{ end -}} reverse_proxy {{ $e.service }} } -{{ end }} +{{ end -}} diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 4605a913..23571d37 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -392,25 +392,40 @@ main() { createDNS bashio::log.info "Configuring Caddy..." - bashio::log.debug "Generating Caddyfile from template in /etc/caddy/Caddyfile" - json=$( + + if + curl -fsSL \ + -H "Authorization: Bearer ${SUPERVISOR_TOKEN}" \ + -H "Content-Type: application/json" \ + http://supervisor/addons/self/info | + jq --exit-status --raw-output '.data.network["443/tcp"]' | + grep -q '^443$' + then + bashio::log.info "Internal port 443/tcp is exposed to host port 443, enabling automatic HTTPS" + auto_https=true + else + bashio::log.info "Internal port 443/tcp is not exposed to host port 443, not enabling automatic HTTPS" + auto_https=false + fi + + tempio_input=$( jq -n \ --arg ha_external_hostname "${external_hostname}" \ --arg ha_port "$(bashio::core.port)" \ --argjson ha_ssl "$(bashio::core.ssl)" \ --argjson additional_hosts "$(jq -c '.additional_hosts' /data/options.json)" \ - '{ha_external_hostname: $ha_external_hostname, ha_port: $ha_port, ha_ssl: $ha_ssl, additional_hosts: $additional_hosts}' + --argjson auto_https "${auto_https}" \ + '{ha_external_hostname: $ha_external_hostname, ha_port: $ha_port, ha_ssl: $ha_ssl, additional_hosts: $additional_hosts, auto_https: $auto_https}' \ ) - bashio::log.debug "JSON: ${json}" - echo "${json}" | tempio -template /etc/caddy/Caddyfile.gtpl -out /etc/caddy/Caddyfile - bashio::log.debug "Generated Caddyfile:" - bashio::log.debug "$(cat /etc/caddy/Caddyfile)" + bashio::log.debug "Tempio input:\n${tempio_input}" + tempio -template /etc/caddy/Caddyfile.gtpl -out /etc/caddy/Caddyfile <<<"${tempio_input}" + bashio::log.debug "Generated Caddyfile:\n$(cat /etc/caddy/Caddyfile)" - # add entries to /etc/hosts + bashio::log.info "Adding entries to /etc/hosts..." echo "127.0.0.1 ${external_hostname}" | tee -a /etc/hosts if bashio::config.has_value 'additional_hosts'; then - for host in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do - echo "127.0.0.1 ${host}" | tee -a /etc/hosts + for hostname in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do + echo "127.0.0.1 ${hostname}" | tee -a /etc/hosts done fi From f84bbcb6eb891a264ab528c824d8ae3c358f8f70 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Fri, 23 May 2025 16:29:08 -0300 Subject: [PATCH 04/55] Clean some things up --- cloudflared/config.yaml | 2 +- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish | 2 +- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run | 4 +--- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cloudflared/config.yaml b/cloudflared/config.yaml index 58ac466f..103a4d5c 100644 --- a/cloudflared/config.yaml +++ b/cloudflared/config.yaml @@ -15,7 +15,6 @@ arch: - armv7 map: - addon_config:rw - - ssl:rw options: external_hostname: "" additional_hosts: [] @@ -25,6 +24,7 @@ ports: 443/tcp: null 443/udp: null privileged: + # https://hub.docker.com/_/caddy#linux-capabilities:~:text=caddy_container_id%20caddy%20reload-,Linux%20capabilities,-Caddy%20ships%20with - NET_ADMIN schema: external_hostname: str? diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish index f75d3a82..eac29699 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish @@ -2,7 +2,7 @@ # shellcheck shell=bash # ============================================================================== # Home Assistant Add-on: Cloudflared -# Take down the S6 supervision tree when the Caddy fails +# Take down the S6 supervision tree when Caddy fails # ============================================================================== readonly exit_code_service="${1}" readonly exit_code_signal="${2}" diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run index 09c0bac2..7d84f99e 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run @@ -2,6 +2,4 @@ # shellcheck shell=bash bashio::log.info "Starting Caddy..." -export XDG_DATA_HOME=/data/caddy-data -export XDG_CONFIG_HOME=/data/caddy-config -exec caddy run --config /etc/caddy/Caddyfile +exec env XDG_DATA_HOME=/data caddy run --config /etc/caddy/Caddyfile diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish index b69d9d66..d14fb7ec 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish @@ -2,7 +2,7 @@ # shellcheck shell=bash # ============================================================================== # Home Assistant Add-on: Cloudflared -# Take down the S6 supervision tree when the cloudflared fails +# Take down the S6 supervision tree when Cloudflared fails # ============================================================================== readonly exit_code_service="${1}" readonly exit_code_signal="${2}" From f642b849a177f56f9ca8fef3394fd2ce18b99918 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Fri, 23 May 2025 16:38:01 -0300 Subject: [PATCH 05/55] More cleanup --- cloudflared/Dockerfile | 2 ++ cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 16 +++++----- .../s6-rc.d/cloudflared/dependencies.d/caddy | 0 .../etc/s6-overlay/s6-rc.d/cloudflared/finish | 29 ------------------- .../etc/s6-overlay/s6-rc.d/cloudflared/type | 1 - .../s6-rc.d/user/contents.d/cloudflared | 0 .../s6-rc.d/cloudflared/run => run.sh} | 0 7 files changed, 10 insertions(+), 38 deletions(-) delete mode 100644 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/dependencies.d/caddy delete mode 100755 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish delete mode 100644 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/type delete mode 100644 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/cloudflared rename cloudflared/rootfs/{etc/s6-overlay/s6-rc.d/cloudflared/run => run.sh} (100%) diff --git a/cloudflared/Dockerfile b/cloudflared/Dockerfile index 2b37da53..ed5aa9b6 100644 --- a/cloudflared/Dockerfile +++ b/cloudflared/Dockerfile @@ -17,6 +17,8 @@ COPY rootfs / # Run the script that installs caddy and cloudflared RUN ["/build.sh"] +CMD ["/run.sh"] + # Build arguments ARG BUILD_DATE ARG BUILD_DESCRIPTION diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 821fd6fd..9c172f37 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -4,16 +4,16 @@ } {{ end -}} {{ .ha_external_hostname }} { - reverse_proxy http://homeassistant:{{ .ha_port }} + reverse_proxy http://homeassistant:{{ .ha_port }} } {{ range $i, $e := .additional_hosts -}} {{ $e.hostname }} { - {{ if $e.internalOnly -}} - @localhost remote_ip 127.0.0.1 - handle @localhost { - respond "This service can only be accessed from local network." 403 - } - {{ end -}} - reverse_proxy {{ $e.service }} + {{ if $e.internalOnly -}} + @localhost remote_ip 127.0.0.1 + handle @localhost { + respond "This service can only be accessed from local network." 403 + } + {{ end -}} + reverse_proxy {{ $e.service }} } {{ end -}} diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/dependencies.d/caddy b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/dependencies.d/caddy deleted file mode 100644 index e69de29b..00000000 diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish deleted file mode 100755 index d14fb7ec..00000000 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/finish +++ /dev/null @@ -1,29 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck shell=bash -# ============================================================================== -# Home Assistant Add-on: Cloudflared -# Take down the S6 supervision tree when Cloudflared fails -# ============================================================================== -readonly exit_code_service="${1}" -readonly exit_code_signal="${2}" -exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode) -readonly exit_code_container -readonly service="cloudflared" - -bashio::log.info \ - "Service ${service} exited with code ${exit_code_service}" \ - "(by signal ${exit_code_signal})" - -if [[ "${exit_code_service}" -eq 256 ]]; then - if [[ "${exit_code_container}" -eq 0 ]]; then - echo $((128 + exit_code_signal)) >/run/s6-linux-init-container-results/exitcode - fi - if [[ "${exit_code_signal}" -eq 15 ]]; then - exec /run/s6/basedir/bin/halt - fi -elif [[ "${exit_code_service}" -ne 0 ]]; then - if [[ "${exit_code_container}" -eq 0 ]]; then - echo "${exit_code_service}" >/run/s6-linux-init-container-results/exitcode - fi - exec /run/s6/basedir/bin/halt -fi diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/type b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/type deleted file mode 100644 index 1780f9f4..00000000 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/type +++ /dev/null @@ -1 +0,0 @@ -longrun \ No newline at end of file diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/cloudflared b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/cloudflared deleted file mode 100644 index e69de29b..00000000 diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/run b/cloudflared/rootfs/run.sh similarity index 100% rename from cloudflared/rootfs/etc/s6-overlay/s6-rc.d/cloudflared/run rename to cloudflared/rootfs/run.sh From 77da04c33facb1c67e8ae7f61d7cbc450f8219bd Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Fri, 23 May 2025 17:26:30 -0300 Subject: [PATCH 06/55] Fix initial certificate generation again --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 8 ++++++++ cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 9c172f37..6cd4cd2e 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -6,6 +6,10 @@ {{ .ha_external_hostname }} { reverse_proxy http://homeassistant:{{ .ha_port }} } +https://{{ .ha_external_hostname }}.localhost { + tls internal + respond 407 +} {{ range $i, $e := .additional_hosts -}} {{ $e.hostname }} { {{ if $e.internalOnly -}} @@ -16,4 +20,8 @@ {{ end -}} reverse_proxy {{ $e.service }} } +https://{{ $e.hostname }}.localhost { + tls internal + respond 407 +} {{ end -}} diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 23571d37..491e0474 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -232,7 +232,7 @@ createConfig() { # Add Service for Home Assistant if 'external_hostname' is set if bashio::config.has_value 'external_hostname'; then if ! bashio::config.has_value 'use_builtin_proxy' || bashio::config.true 'use_builtin_proxy'; then - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"https://${external_hostname}\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"https://${external_hostname}.localhost\"}]") else config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_service_protocol}://homeassistant:$(bashio::core.port)\"}]") fi @@ -250,7 +250,7 @@ createConfig() { fi if ! bashio::config.has_value 'use_builtin_proxy' || bashio::config.true 'use_builtin_proxy'; then - additional_host=$(bashio::jq "${additional_host}" '.service = "https://\(.hostname)"') + additional_host=$(bashio::jq "${additional_host}" '.service = "https://\(.hostname).localhost"') fi additional_host=$(bashio::jq "${additional_host}" "del(.internalOnly)") @@ -422,10 +422,10 @@ main() { bashio::log.debug "Generated Caddyfile:\n$(cat /etc/caddy/Caddyfile)" bashio::log.info "Adding entries to /etc/hosts..." - echo "127.0.0.1 ${external_hostname}" | tee -a /etc/hosts + echo "127.0.0.1 ${external_hostname}.localhost" | tee -a /etc/hosts if bashio::config.has_value 'additional_hosts'; then for hostname in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do - echo "127.0.0.1 ${hostname}" | tee -a /etc/hosts + echo "127.0.0.1 ${hostname}.localhost" | tee -a /etc/hosts done fi From 95b5f53a9218b1a82211679fff7f9726ce8111de Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sat, 24 May 2025 01:08:52 -0300 Subject: [PATCH 07/55] More cleanup --- .github/workflows/ci.yaml | 4 ---- .github/workflows/deploy.yaml | 5 ----- 2 files changed, 9 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1c5082c9..9f15b576 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -142,8 +142,6 @@ jobs: id: flags run: | echo "date=$(date +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT - from=$(yq --no-colors eval ".build_from.${{ matrix.architecture }}" "${{ needs.information.outputs.build }}") - echo "from=$from" >> $GITHUB_OUTPUT if [[ "${{ matrix.architecture}}" = "amd64" ]]; then echo "platform=linux/amd64" >> $GITHUB_OUTPUT elif [[ "${{ matrix.architecture }}" = "armv7" ]]; then @@ -154,8 +152,6 @@ jobs: echo "::error ::Could not determine platform for architecture ${{ matrix.architecture }}" exit 1 fi - - name: ⤵️ Download base image - run: docker pull "${{ steps.flags.outputs.from }}" - name: 🚀 Build uses: docker/build-push-action@v6.17.0 with: diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 0266cda2..2a73afcb 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -86,8 +86,6 @@ jobs: id: flags run: | echo "date=$(date +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_OUTPUT - from=$(yq --no-colors eval ".build_from.${{ matrix.architecture }}" "${{ needs.information.outputs.build }}") - echo "from=$from" >> $GITHUB_OUTPUT if [[ "${{ matrix.architecture}}" = "amd64" ]]; then echo "platform=linux/amd64" >> $GITHUB_OUTPUT elif [[ "${{ matrix.architecture }}" = "armv7" ]]; then @@ -104,8 +102,6 @@ jobs: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: ⤵️ Download base image - run: docker pull "${{ steps.flags.outputs.from }}" - name: 🚀 Build uses: docker/build-push-action@v6.17.0 with: @@ -124,7 +120,6 @@ jobs: BUILD_ARCH=${{ matrix.architecture }} BUILD_DATE=${{ steps.flags.outputs.date }} BUILD_DESCRIPTION=${{ needs.information.outputs.description }} - BUILD_FROM=${{ steps.flags.outputs.from }} BUILD_NAME=${{ needs.information.outputs.name }} BUILD_REF=${{ github.sha }} BUILD_REPOSITORY=${{ github.repository }} From e3d320203f20be94b98d6c6b924bdca4930444cd Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sat, 24 May 2025 01:19:45 -0300 Subject: [PATCH 08/55] Handle SSL in service and HA --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 28 ++++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 6cd4cd2e..af87aa1c 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -1,27 +1,43 @@ -{{ if not .auto_https -}} +{{ if not .auto_https }} { local_certs } -{{ end -}} +{{ end }} {{ .ha_external_hostname }} { + {{ if .ha_ssl }} + reverse_proxy https://homeassistant:{{ .ha_port }} { + transport http { + tls_insecure_skip_verify + } + } + {{ else }} reverse_proxy http://homeassistant:{{ .ha_port }} + {{ end }} } https://{{ .ha_external_hostname }}.localhost { tls internal respond 407 } -{{ range $i, $e := .additional_hosts -}} +{{ range $i, $e := .additional_hosts }} {{ $e.hostname }} { - {{ if $e.internalOnly -}} + {{ if $e.internalOnly }} @localhost remote_ip 127.0.0.1 handle @localhost { respond "This service can only be accessed from local network." 403 } - {{ end -}} + {{ end }} + {{ if hasPrefix "https://" $e.service }} + reverse_proxy {{ $e.service }} { + transport http { + tls_insecure_skip_verify + } + } + {{ else }} reverse_proxy {{ $e.service }} + {{ end }} } https://{{ $e.hostname }}.localhost { tls internal respond 407 } -{{ end -}} +{{ end }} From 529a625705413bed65e45d52b56666eaa841592e Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 26 May 2025 20:56:53 -0300 Subject: [PATCH 09/55] Update docs and avoid starting caddy when built-in proxy is disabled --- cloudflared/DOCS.md | 39 ++++++- cloudflared/config.yaml | 3 +- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 6 +- .../etc/s6-overlay/s6-rc.d/caddy/finish | 5 + .../rootfs/etc/s6-overlay/s6-rc.d/caddy/run | 6 ++ .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 101 +++++++++++------- cloudflared/rootfs/run.sh | 3 +- cloudflared/translations/en.yaml | 13 ++- 8 files changed, 125 insertions(+), 51 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index 2356591b..fe13a1a0 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -220,12 +220,45 @@ them to wherever you like. ### Option: `use_builtin_proxy` -If enabled, the connection to Home Assistant will be made through the built-in -Nginx proxy. Nginx was implemented as a workaround for issues with live logs. -For reference, see discussion [#744](https://github.com/brenner-tobias/addon-cloudflared/discussions/744) +If enabled, the connection to Home Assistant and additional hosts will be made +through the built-in Caddy proxy. This works around issues with live logs ([#744](https://github.com/brenner-tobias/addon-cloudflared/discussions/744)) +and allows an unified access to Home Assistant and additional hosts even within +your local network. **Note**: _This option is enabled by default._ +Here is how you can leverage the built-in proxy for local access: + +1. Expose these additional add-on ports: + - `80/tcp` for HTTP access + - `443/tcp` for HTTPS access (this will also enable automatic HTTPS certificates and HTTP to HTTPS redirection) + - `443/udp` for HTTP/3 QUIC access +2. Set your local DNS server to resolve the `external_hostname` and + `additional_hosts` to the local IP of your Home Assistant instance. + + Example: set `ha.example.com` and `router.example.com` to resolve to + `192.168.1.10`. + + If you are using OpenWRT, you can do it from _Network_ > _DHCP and DNS_ > _DNS Records_ > _Hostnames_. +3. Confirm that the `external_hostname` and `additional_hosts` are + resolving to the local IP of your Home Assistant. + + Example: run `nslookup ha.example.com` in your terminal and check that the + output shows the local IP of your Home Assistant instance, and not + Cloudflare's IP addresses. +4. Access your Home Assistant instance via the `external_hostname` or + `additional_hosts` in your browser. + + Example: `https://ha.example.com/` or `https://router.example.com/`. + + And confirm everything works as expected. + +Congratulations! You are now using the built-in proxy to access your Home +Assistant instance and additional hosts locally, through an unified URL without +having to go swap between internal and external URLs. Also, you saved a lot of +time by not having to set up a reverse proxy like Nginx Proxy Manager yourself, +including handling the HTTPS certificates and HTTP to HTTPS redirection. + ### Option: `post_quantum` If you want Cloudflared to use post-quantum cryptography for the tunnel, diff --git a/cloudflared/config.yaml b/cloudflared/config.yaml index 103a4d5c..43857716 100644 --- a/cloudflared/config.yaml +++ b/cloudflared/config.yaml @@ -1,6 +1,6 @@ --- name: Cloudflared -version: dev +version: dev-1 slug: cloudflared description: "Use a Cloudflare Tunnel to remotely connect to Home Assistant without opening any ports" @@ -18,6 +18,7 @@ map: options: external_hostname: "" additional_hosts: [] + use_builtin_proxy: true ports: 36500/tcp: null 80/tcp: null diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index af87aa1c..c63242eb 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -4,14 +4,14 @@ } {{ end }} {{ .ha_external_hostname }} { - {{ if .ha_ssl }} - reverse_proxy https://homeassistant:{{ .ha_port }} { + {{ if hasPrefix "https://" .ha_service_url }} + reverse_proxy {{ .ha_service_url }} { transport http { tls_insecure_skip_verify } } {{ else }} - reverse_proxy http://homeassistant:{{ .ha_port }} + reverse_proxy {{ .ha_service_url }} {{ end }} } https://{{ .ha_external_hostname }}.localhost { diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish index eac29699..c1790bbe 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish @@ -4,6 +4,11 @@ # Home Assistant Add-on: Cloudflared # Take down the S6 supervision tree when Caddy fails # ============================================================================== + +if [[ -f /dev/shm/no_built_in_proxy ]]; then + exit 0 +fi + readonly exit_code_service="${1}" readonly exit_code_signal="${2}" exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run index 7d84f99e..6157377b 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run @@ -1,5 +1,11 @@ #!/command/with-contenv bashio # shellcheck shell=bash +if [[ -f /dev/shm/no_built_in_proxy ]]; then + # Tell S6-Overlay not to restart this service + s6-svc -O . + exit 0 +fi + bashio::log.info "Starting Caddy..." exec env XDG_DATA_HOME=/data caddy run --config /etc/caddy/Caddyfile diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 491e0474..e90b7c76 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -229,12 +229,14 @@ createConfig() { bashio::exit.nok "Error checking if SSL is enabled" fi + ha_service_url="${ha_service_protocol}://homeassistant:$(bashio::core.port)" + # Add Service for Home Assistant if 'external_hostname' is set if bashio::config.has_value 'external_hostname'; then - if ! bashio::config.has_value 'use_builtin_proxy' || bashio::config.true 'use_builtin_proxy'; then + if bashio::var.true "${use_builtin_proxy}"; then config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"https://${external_hostname}.localhost\"}]") else - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_service_protocol}://homeassistant:$(bashio::core.port)\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_service_url}\"}]") fi fi @@ -249,10 +251,14 @@ createConfig() { additional_host=$(bashio::jq "${additional_host}" ".originRequest += {\"disableChunkedEncoding\": ${disableChunkedEncoding}}") fi - if ! bashio::config.has_value 'use_builtin_proxy' || bashio::config.true 'use_builtin_proxy'; then + # Make Cloudflared always reach the Caddy proxy if enabled + if bashio::var.true "${use_builtin_proxy}"; then additional_host=$(bashio::jq "${additional_host}" '.service = "https://\(.hostname).localhost"') + elif bashio::var.true "$(bashio::jq "${additional_host}" ".internalOnly")"; then + bashio::exit.nok "'additional_hosts.internalOnly' is only supported when using the built-in Caddy proxy. Please set 'use_builtin_proxy' to true or remove 'internalOnly' from the additional host configuration." fi + # internalOnly is only for Caddy, not for Cloudflared additional_host=$(bashio::jq "${additional_host}" "del(.internalOnly)") # Add additional_host config to ingress config @@ -344,6 +350,50 @@ setCloudflaredLogLevel() { } +configureCaddy() { + bashio::log.info "Configuring built-in Caddy proxy..." + + if + curl -fsSL \ + -H "Authorization: Bearer ${SUPERVISOR_TOKEN}" \ + -H "Content-Type: application/json" \ + http://supervisor/addons/self/info | + jq --exit-status --raw-output '.data.network["443/tcp"]' | + grep -q '^443$' + then + bashio::log.info "Internal port 443/tcp is exposed to host port 443, enabling automatic HTTPS" + auto_https=true + else + bashio::log.info "Internal port 443/tcp is not exposed to host port 443, not enabling automatic HTTPS" + auto_https=false + fi + + bashio::log.info "Generating Caddyfile..." + tempio_input=$( + jq -n \ + --arg ha_external_hostname "${external_hostname}" \ + --arg ha_service_url "${ha_service_url}" \ + --argjson additional_hosts "$(jq -c '.additional_hosts' /data/options.json)" \ + --argjson auto_https "${auto_https}" \ + '{ha_external_hostname: $ha_external_hostname, ha_service_url: $ha_service_url, additional_hosts: $additional_hosts, auto_https: $auto_https}' + ) + bashio::log.debug "Tempio input:\n${tempio_input}" + tempio -template /etc/caddy/Caddyfile.gtpl -out /etc/caddy/Caddyfile <<<"${tempio_input}" + bashio::log.debug "Generated Caddyfile:\n$(cat /etc/caddy/Caddyfile)" + + bashio::log.info "Validating Caddyfile..." + caddy fmt --overwrite --config /etc/caddy/Caddyfile || bashio::exit.nok "Caddyfile formatting failed, please check the logs above." + caddy validate --config /etc/caddy/Caddyfile || bashio::exit.nok "Caddyfile validation failed, please check the logs above." + + bashio::log.info "Adding host entries for Cloudflared to communicate with Caddy..." + echo "127.0.0.1 ${external_hostname}.localhost" | tee -a /etc/hosts + if bashio::config.has_value 'additional_hosts'; then + for hostname in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do + echo "127.0.0.1 ${hostname}.localhost" | tee -a /etc/hosts + done + fi +} + # ============================================================================== # RUN LOGIC # ------------------------------------------------------------------------------ @@ -379,6 +429,12 @@ main() { external_hostname="$(bashio::config 'external_hostname')" + if bashio::config.true 'use_builtin_proxy'; then + use_builtin_proxy=true + else + use_builtin_proxy=false + fi + if ! hasCertificate; then createCertificate fi @@ -391,42 +447,11 @@ main() { createDNS - bashio::log.info "Configuring Caddy..." - - if - curl -fsSL \ - -H "Authorization: Bearer ${SUPERVISOR_TOKEN}" \ - -H "Content-Type: application/json" \ - http://supervisor/addons/self/info | - jq --exit-status --raw-output '.data.network["443/tcp"]' | - grep -q '^443$' - then - bashio::log.info "Internal port 443/tcp is exposed to host port 443, enabling automatic HTTPS" - auto_https=true + if bashio::var.true "${use_builtin_proxy}"; then + configureCaddy else - bashio::log.info "Internal port 443/tcp is not exposed to host port 443, not enabling automatic HTTPS" - auto_https=false - fi - - tempio_input=$( - jq -n \ - --arg ha_external_hostname "${external_hostname}" \ - --arg ha_port "$(bashio::core.port)" \ - --argjson ha_ssl "$(bashio::core.ssl)" \ - --argjson additional_hosts "$(jq -c '.additional_hosts' /data/options.json)" \ - --argjson auto_https "${auto_https}" \ - '{ha_external_hostname: $ha_external_hostname, ha_port: $ha_port, ha_ssl: $ha_ssl, additional_hosts: $additional_hosts, auto_https: $auto_https}' \ - ) - bashio::log.debug "Tempio input:\n${tempio_input}" - tempio -template /etc/caddy/Caddyfile.gtpl -out /etc/caddy/Caddyfile <<<"${tempio_input}" - bashio::log.debug "Generated Caddyfile:\n$(cat /etc/caddy/Caddyfile)" - - bashio::log.info "Adding entries to /etc/hosts..." - echo "127.0.0.1 ${external_hostname}.localhost" | tee -a /etc/hosts - if bashio::config.has_value 'additional_hosts'; then - for hostname in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do - echo "127.0.0.1 ${hostname}.localhost" | tee -a /etc/hosts - done + bashio::log.info "Using Cloudflared without built-in Caddy proxy" + touch /dev/shm/no_built_in_proxy fi bashio::log.info "Finished setting up the Cloudflare Tunnel" diff --git a/cloudflared/rootfs/run.sh b/cloudflared/rootfs/run.sh index f56339eb..5aada2eb 100755 --- a/cloudflared/rootfs/run.sh +++ b/cloudflared/rootfs/run.sh @@ -40,5 +40,4 @@ fi bashio::log.info "Connecting Cloudflare Tunnel..." bashio::log.debug "cloudflared tunnel ${options[*]}" -exec cloudflared \ - tunnel "${options[@]}" +exec cloudflared tunnel "${options[@]}" diff --git a/cloudflared/translations/en.yaml b/cloudflared/translations/en.yaml index ed297dea..c93771e2 100644 --- a/cloudflared/translations/en.yaml +++ b/cloudflared/translations/en.yaml @@ -40,10 +40,12 @@ configuration: Sets the catch-all service to the "Nginx-Proxy-Manager Community Add-Ons" Add-on. use_builtin_proxy: - name: Use built-in Nginx proxy + name: Use built-in Caddy proxy description: >- - The connection to Home Assistant will be made through the built-in - Nginx proxy. (Workaround for issues with live logs). + The connection to Home Assistant and additional hosts will be made + through the built-in Caddy proxy. This works around issues with live logs + and allows an unified access to Home Assistant and additional hosts even + within your local network, read the documentation for more details. This option is enabled by default. tunnel_token: name: Cloudflare Tunnel Token @@ -51,4 +53,7 @@ configuration: When set all other options will be ignored. Use this option if you set up the tunnel with the Cloudflare Dashboard. network: - 36500/tcp: Metrics Web Interface (36500/tcp) + 36500/tcp: Metrics Web Interface + 80/tcp: Built-in Caddy Proxy HTTP Interface + 443/tcp: Built-in Caddy Proxy HTTPS Interface + 443/udp: Built-in Caddy Proxy HTTP/3 QUIC Interface From 5f6abbbdac64f1c47535d11820c085f729e21d50 Mon Sep 17 00:00:00 2001 From: felipecrs Date: Mon, 26 May 2025 23:57:05 +0000 Subject: [PATCH 10/55] Prettified Code! --- cloudflared/DOCS.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index fe13a1a0..d506f524 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -235,20 +235,22 @@ Here is how you can leverage the built-in proxy for local access: - `443/udp` for HTTP/3 QUIC access 2. Set your local DNS server to resolve the `external_hostname` and `additional_hosts` to the local IP of your Home Assistant instance. - - Example: set `ha.example.com` and `router.example.com` to resolve to + + Example: set `ha.example.com` and `router.example.com` to resolve to `192.168.1.10`. If you are using OpenWRT, you can do it from _Network_ > _DHCP and DNS_ > _DNS Records_ > _Hostnames_. + 3. Confirm that the `external_hostname` and `additional_hosts` are resolving to the local IP of your Home Assistant. - + Example: run `nslookup ha.example.com` in your terminal and check that the output shows the local IP of your Home Assistant instance, and not Cloudflare's IP addresses. + 4. Access your Home Assistant instance via the `external_hostname` or `additional_hosts` in your browser. - + Example: `https://ha.example.com/` or `https://router.example.com/`. And confirm everything works as expected. From 539b3e2ffeff41cb74744c265cbba57f15ae543f Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 26 May 2025 21:18:07 -0300 Subject: [PATCH 11/55] Setup catch all service --- cloudflared/DOCS.md | 4 ++ cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 7 ++++ .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 37 +++++++++++-------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index d506f524..f1866316 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -129,6 +129,10 @@ chunked transfer encoding. This is useful if you are running a WSGI server, like Proxmox for example. Visit [Cloudflare Docs][disablechunkedencoding] for further information. +When `use_builtin_proxy` is enabled, you can also add `internalOnly: true` to a +hostname to only allow access to it from within your local network. When this +service is accessed from Cloudflare, it will return a 403 Forbidden. + Please find below an example entry for three additional hosts: ```yaml diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index c63242eb..78ff65b7 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -41,3 +41,10 @@ https://{{ $e.hostname }}.localhost { respond 407 } {{ end }} +:80 { + {{ if .catch_all_service }} + reverse_proxy {{ .catch_all_service }} + {{ else }} + respond "This service was not found." 404 + {{ end }} +} diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index e90b7c76..afd26695 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -266,23 +266,19 @@ createConfig() { done <<<"$(jq -c '.additional_hosts[]' /data/options.json)" fi - # Check if NGINX Proxy Manager is used to finalize configuration - if bashio::config.true 'nginx_proxy_manager'; then - + if bashio::var.true "${use_builtin_proxy}"; then + bashio::log.info "Setting catch all service in Cloudflared to Caddy proxy" + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://127.0.0.1:80\"}]") + elif bashio::config.true 'nginx_proxy_manager'; then bashio::log.warning "Runing with Nginxproxymanager support, make sure the add-on is installed and running." config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://a0d7b954-nginxproxymanager:80\"}]") + elif bashio::config.has_value 'catch_all_service'; then + bashio::log.info "Runing with Catch all Service" + # Setting catch all service to defined URL + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"$(bashio::config 'catch_all_service')\"}]") else - - # Check if catch all service is defined - if bashio::config.has_value 'catch_all_service'; then - - bashio::log.info "Runing with Catch all Service" - # Setting catch all service to defined URL - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"$(bashio::config 'catch_all_service')\"}]") - else - # Finalize config without NPM support and catch all service, sending all other requests to HTTP:404 - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http_status:404\"}]") - fi + # Finalize config without NPM support and catch all service, sending all other requests to HTTP:404 + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http_status:404\"}]") fi # Deactivate TLS verification for all services @@ -368,14 +364,25 @@ configureCaddy() { auto_https=false fi + if bashio::config.true 'nginx_proxy_manager'; then + bashio::log.warning "Runing with Nginxproxymanager support, make sure the add-on is installed and running." + catch_all_service="http://a0d7b954-nginxproxymanager:80" + elif bashio::config.has_value 'catch_all_service'; then + bashio::log.info "Runing with Catch all Service" + catch_all_service="$(bashio::config 'catch_all_service')" + else + catch_all_service="" + fi + bashio::log.info "Generating Caddyfile..." tempio_input=$( jq -n \ --arg ha_external_hostname "${external_hostname}" \ --arg ha_service_url "${ha_service_url}" \ + --arg catch_all_service "${catch_all_service}" \ --argjson additional_hosts "$(jq -c '.additional_hosts' /data/options.json)" \ --argjson auto_https "${auto_https}" \ - '{ha_external_hostname: $ha_external_hostname, ha_service_url: $ha_service_url, additional_hosts: $additional_hosts, auto_https: $auto_https}' + '{ha_external_hostname: $ha_external_hostname, ha_service_url: $ha_service_url, catch_all_service: $catch_all_service, additional_hosts: $additional_hosts, auto_https: $auto_https}' ) bashio::log.debug "Tempio input:\n${tempio_input}" tempio -template /etc/caddy/Caddyfile.gtpl -out /etc/caddy/Caddyfile <<<"${tempio_input}" From 01f3a3925826f6ed8d40a14fbcdade56ca71dc74 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 26 May 2025 21:18:59 -0300 Subject: [PATCH 12/55] Restore addon version --- cloudflared/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudflared/config.yaml b/cloudflared/config.yaml index 43857716..02a4a8c2 100644 --- a/cloudflared/config.yaml +++ b/cloudflared/config.yaml @@ -1,6 +1,6 @@ --- name: Cloudflared -version: dev-1 +version: dev slug: cloudflared description: "Use a Cloudflare Tunnel to remotely connect to Home Assistant without opening any ports" From 681e6556c8473ec1506c8fe89f2d96f6ee029c80 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 26 May 2025 21:22:39 -0300 Subject: [PATCH 13/55] Fix some markdown lint --- cloudflared/DOCS.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index f1866316..df5b98e4 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -234,16 +234,20 @@ your local network. Here is how you can leverage the built-in proxy for local access: 1. Expose these additional add-on ports: + - `80/tcp` for HTTP access - - `443/tcp` for HTTPS access (this will also enable automatic HTTPS certificates and HTTP to HTTPS redirection) + - `443/tcp` for HTTPS access (this will also enable automatic HTTPS + certificates and HTTP to HTTPS redirection) - `443/udp` for HTTP/3 QUIC access + 2. Set your local DNS server to resolve the `external_hostname` and `additional_hosts` to the local IP of your Home Assistant instance. Example: set `ha.example.com` and `router.example.com` to resolve to `192.168.1.10`. - If you are using OpenWRT, you can do it from _Network_ > _DHCP and DNS_ > _DNS Records_ > _Hostnames_. + If you are using OpenWRT, you can do it from _Network_ > _DHCP and DNS_ > + _DNS Records_ > _Hostnames_. 3. Confirm that the `external_hostname` and `additional_hosts` are resolving to the local IP of your Home Assistant. From 51150d669af1f507382f206389fdb5a34d9656f6 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 26 May 2025 21:31:38 -0300 Subject: [PATCH 14/55] Fix another one --- cloudflared/DOCS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index df5b98e4..346a148f 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -240,7 +240,7 @@ Here is how you can leverage the built-in proxy for local access: certificates and HTTP to HTTPS redirection) - `443/udp` for HTTP/3 QUIC access -2. Set your local DNS server to resolve the `external_hostname` and +1. Set your local DNS server to resolve the `external_hostname` and `additional_hosts` to the local IP of your Home Assistant instance. Example: set `ha.example.com` and `router.example.com` to resolve to @@ -249,14 +249,14 @@ Here is how you can leverage the built-in proxy for local access: If you are using OpenWRT, you can do it from _Network_ > _DHCP and DNS_ > _DNS Records_ > _Hostnames_. -3. Confirm that the `external_hostname` and `additional_hosts` are +1. Confirm that the `external_hostname` and `additional_hosts` are resolving to the local IP of your Home Assistant. Example: run `nslookup ha.example.com` in your terminal and check that the output shows the local IP of your Home Assistant instance, and not Cloudflare's IP addresses. -4. Access your Home Assistant instance via the `external_hostname` or +1. Access your Home Assistant instance via the `external_hostname` or `additional_hosts` in your browser. Example: `https://ha.example.com/` or `https://router.example.com/`. From 11c65214be7b0f8ec4b1d9276cdcb7dbbf665a75 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 26 May 2025 21:35:45 -0300 Subject: [PATCH 15/55] Add bullet point for internalOnly --- cloudflared/DOCS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index 346a148f..cae2568e 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -263,6 +263,11 @@ Here is how you can leverage the built-in proxy for local access: And confirm everything works as expected. +1. Optionally, you can set `additional_hosts` entries with `internalOnly: true` + to only allow access to them from within your local network. When such + service is accessed from Cloudflare, it will return a 403 Forbidden. Don't + forget to set the DNS entries for these hosts too. + Congratulations! You are now using the built-in proxy to access your Home Assistant instance and additional hosts locally, through an unified URL without having to go swap between internal and external URLs. Also, you saved a lot of From c48b07afc4d5cbce5c34fb008de9baceab036a97 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 26 May 2025 22:00:33 -0300 Subject: [PATCH 16/55] Fix some @coderabiitai comments --- cloudflared/DOCS.md | 6 +++--- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index cae2568e..4d82f134 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -226,7 +226,7 @@ them to wherever you like. If enabled, the connection to Home Assistant and additional hosts will be made through the built-in Caddy proxy. This works around issues with live logs ([#744](https://github.com/brenner-tobias/addon-cloudflared/discussions/744)) -and allows an unified access to Home Assistant and additional hosts even within +and allows a unified access to Home Assistant and additional hosts even within your local network. **Note**: _This option is enabled by default._ @@ -269,8 +269,8 @@ Here is how you can leverage the built-in proxy for local access: forget to set the DNS entries for these hosts too. Congratulations! You are now using the built-in proxy to access your Home -Assistant instance and additional hosts locally, through an unified URL without -having to go swap between internal and external URLs. Also, you saved a lot of +Assistant instance and additional hosts locally, through a unified URL without +having to swap between internal and external URLs. Also, you saved a lot of time by not having to set up a reverse proxy like Nginx Proxy Manager yourself, including handling the HTTPS certificates and HTTP to HTTPS redirection. diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 78ff65b7..04b3f1ea 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -21,6 +21,7 @@ https://{{ .ha_external_hostname }}.localhost { {{ range $i, $e := .additional_hosts }} {{ $e.hostname }} { {{ if $e.internalOnly }} + # Block connections from Cloudflared as service is internal only @localhost remote_ip 127.0.0.1 handle @localhost { respond "This service can only be accessed from local network." 403 From f5a99651bf279599646e2401168847b91c04dcc7 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Tue, 10 Jun 2025 21:55:29 -0300 Subject: [PATCH 17/55] Address some comments --- cloudflared/DOCS.md | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index 4d82f134..2312fa5a 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -233,15 +233,24 @@ your local network. Here is how you can leverage the built-in proxy for local access: -1. Expose these additional add-on ports: +1. These additional add-on ports needs to be exposed through the add-on + _Configuration_ page > _Network_: - `80/tcp` for HTTP access - `443/tcp` for HTTPS access (this will also enable automatic HTTPS certificates and HTTP to HTTPS redirection) - `443/udp` for HTTP/3 QUIC access -1. Set your local DNS server to resolve the `external_hostname` and - `additional_hosts` to the local IP of your Home Assistant instance. + To expose them, click _Show disabled ports_ and repeat their port numbers in + each of them: + + - `80` for the `80/tcp` port + - `443` for the `443/tcp` port + - `443` for the `443/udp` port + +1. Set your local DNS server to resolve the `external_hostname` and any + `hostname` of `additional_hosts` to the local IP of your Home Assistant + instance. Example: set `ha.example.com` and `router.example.com` to resolve to `192.168.1.10`. @@ -249,15 +258,20 @@ Here is how you can leverage the built-in proxy for local access: If you are using OpenWRT, you can do it from _Network_ > _DHCP and DNS_ > _DNS Records_ > _Hostnames_. -1. Confirm that the `external_hostname` and `additional_hosts` are - resolving to the local IP of your Home Assistant. + If you are using AdGuard Home, you can do it from _Filters_ > _DNS rewrites_. + + If you are using some other DNS server, please refer to its documentation. + +1. Confirm that the `external_hostname` and any `hostname` of `additional_hosts` + are resolving to the local IP of your Home Assistant. - Example: run `nslookup ha.example.com` in your terminal and check that the - output shows the local IP of your Home Assistant instance, and not - Cloudflare's IP addresses. + Example: run `nslookup ha.example.com` and `nslookup router.example.com` in + your terminal and check that the output shows the local IP of your Home + Assistant instance, and not Cloudflare's IP addresses. -1. Access your Home Assistant instance via the `external_hostname` or - `additional_hosts` in your browser. +1. Access your Home Assistant instance via the `external_hostname` or access + your additional hosts via their `hostname`s defined in `additional_hosts` in + your browser. Example: `https://ha.example.com/` or `https://router.example.com/`. @@ -265,7 +279,7 @@ Here is how you can leverage the built-in proxy for local access: 1. Optionally, you can set `additional_hosts` entries with `internalOnly: true` to only allow access to them from within your local network. When such - service is accessed from Cloudflare, it will return a 403 Forbidden. Don't + service is accessed from Cloudflare, it will return a _403 Forbidden_. Don't forget to set the DNS entries for these hosts too. Congratulations! You are now using the built-in proxy to access your Home From 2990d7560ddf88ad757b5b3950232bdabeff7eb9 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Tue, 10 Jun 2025 22:28:58 -0300 Subject: [PATCH 18/55] Refactor Caddyfile --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 04b3f1ea..2b9cb157 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -1,8 +1,10 @@ {{ if not .auto_https }} { + # Disable automatic generation of Let's Encrypt certificates local_certs } {{ end }} + {{ .ha_external_hostname }} { {{ if hasPrefix "https://" .ha_service_url }} reverse_proxy {{ .ha_service_url }} { @@ -14,10 +16,7 @@ reverse_proxy {{ .ha_service_url }} {{ end }} } -https://{{ .ha_external_hostname }}.localhost { - tls internal - respond 407 -} + {{ range $i, $e := .additional_hosts }} {{ $e.hostname }} { {{ if $e.internalOnly }} @@ -37,11 +36,9 @@ https://{{ .ha_external_hostname }}.localhost { reverse_proxy {{ $e.service }} {{ end }} } -https://{{ $e.hostname }}.localhost { - tls internal - respond 407 -} {{ end }} + +# Catch-all service for any unmatched requests :80 { {{ if .catch_all_service }} reverse_proxy {{ .catch_all_service }} @@ -49,3 +46,11 @@ https://{{ $e.hostname }}.localhost { respond "This service was not found." 404 {{ end }} } + +{{ if .auto_https }} +# Only used during automatic Let's Encrypt certificate generation +https://{{ .ha_external_hostname }}.localhost {{ range $i, $e := .additional_hosts }}https://{{ $e.hostname }}.localhost {{ end }} { + tls internal + respond 407 +} +{{ end }} From 8ce10285c5e89686d1cd56c6936269cc18748f7d Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 11 Jun 2025 14:28:09 -0300 Subject: [PATCH 19/55] Improve condition name --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 2b9cb157..c2559c93 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -21,11 +21,12 @@ {{ $e.hostname }} { {{ if $e.internalOnly }} # Block connections from Cloudflared as service is internal only - @localhost remote_ip 127.0.0.1 - handle @localhost { + @cloudflared remote_ip 127.0.0.1 + handle @cloudflared { respond "This service can only be accessed from local network." 403 } {{ end }} + {{ if hasPrefix "https://" $e.service }} reverse_proxy {{ $e.service }} { transport http { From fb434455977446cad2016141c018f6840ba17056 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 11 Jun 2025 15:25:48 -0300 Subject: [PATCH 20/55] Handle catch all service with https --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index c2559c93..0f750c71 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -42,7 +42,15 @@ # Catch-all service for any unmatched requests :80 { {{ if .catch_all_service }} + {{ if hasPrefix "https://" .catch_all_service }} + reverse_proxy {{ .catch_all_service }} { + transport http { + tls_insecure_skip_verify + } + } + {{ else }} reverse_proxy {{ .catch_all_service }} + {{ end }} {{ else }} respond "This service was not found." 404 {{ end }} From 159cb8e2fe013fa3c5ef706b7a78ea2ee0ea66f1 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 11 Jun 2025 22:19:54 -0300 Subject: [PATCH 21/55] Fix 127.0.0.1 login notifications with Caddy --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 33 +++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 0f750c71..60506334 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -6,6 +6,16 @@ {{ end }} {{ .ha_external_hostname }} { + @cloudflared remote_ip 127.0.0.1 + # https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/#caddy + reverse_proxy @cloudflared {{ .ha_service_url }} { + header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} + {{ if hasPrefix "https://" .ha_service_url }} + transport http { + tls_insecure_skip_verify + } + {{ end }} + } {{ if hasPrefix "https://" .ha_service_url }} reverse_proxy {{ .ha_service_url }} { transport http { @@ -19,14 +29,23 @@ {{ range $i, $e := .additional_hosts }} {{ $e.hostname }} { + @cloudflared remote_ip 127.0.0.1 {{ if $e.internalOnly }} # Block connections from Cloudflared as service is internal only - @cloudflared remote_ip 127.0.0.1 handle @cloudflared { respond "This service can only be accessed from local network." 403 } + {{ else }} + # https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/#caddy + reverse_proxy @cloudflared {{ $e.service }} { + header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} + {{ if hasPrefix "https://" $e.service }} + transport http { + tls_insecure_skip_verify + } + {{ end }} + } {{ end }} - {{ if hasPrefix "https://" $e.service }} reverse_proxy {{ $e.service }} { transport http { @@ -41,7 +60,17 @@ # Catch-all service for any unmatched requests :80 { + @cloudflared remote_ip 127.0.0.1 {{ if .catch_all_service }} + # https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/#caddy + reverse_proxy @cloudflared {{ .catch_all_service }} { + header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} + {{ if hasPrefix "https://" .catch_all_service }} + transport http { + tls_insecure_skip_verify + } + {{ end }} + } {{ if hasPrefix "https://" .catch_all_service }} reverse_proxy {{ .catch_all_service }} { transport http { From 97ea8a6bf884964ef2a3b2c3d6ea20d32e43f66e Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 11 Jun 2025 23:04:54 -0300 Subject: [PATCH 22/55] Wait for Caddy to be ready before starting Cloudflared --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 6 ++++++ cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 1 + cloudflared/rootfs/run.sh | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 60506334..162cd11c 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -5,6 +5,12 @@ } {{ end }} +# Allows to wait for Caddy to be ready before starting Cloudflared +https://healthcheck.localhost { + tls internal + respond "OK" 200 +} + {{ .ha_external_hostname }} { @cloudflared remote_ip 127.0.0.1 # https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/#caddy diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index afd26695..c00bf7bb 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -393,6 +393,7 @@ configureCaddy() { caddy validate --config /etc/caddy/Caddyfile || bashio::exit.nok "Caddyfile validation failed, please check the logs above." bashio::log.info "Adding host entries for Cloudflared to communicate with Caddy..." + echo "127.0.0.1 healthcheck.localhost" | tee -a /etc/hosts echo "127.0.0.1 ${external_hostname}.localhost" | tee -a /etc/hosts if bashio::config.has_value 'additional_hosts'; then for hostname in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do diff --git a/cloudflared/rootfs/run.sh b/cloudflared/rootfs/run.sh index 5aada2eb..c335bd9e 100755 --- a/cloudflared/rootfs/run.sh +++ b/cloudflared/rootfs/run.sh @@ -38,6 +38,13 @@ else options+=(run "$(bashio::config 'tunnel_name')") fi +if [[ ! -f /dev/shm/no_built_in_proxy ]]; then + bashio::log.info "Waiting for Caddy to be ready..." + if ! curl --fail --silent --show-error --max-time 1 --retry 15 --retry-delay 1 --retry-connrefused --insecure https://healthcheck.localhost; then + bashio::exit.nok "Caddy did not become ready in time, aborting." + fi +fi + bashio::log.info "Connecting Cloudflare Tunnel..." bashio::log.debug "cloudflared tunnel ${options[*]}" exec cloudflared tunnel "${options[@]}" From 8b95267419bba08cd7454dfa1b50c438cd267951 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 11 Jun 2025 23:42:10 -0300 Subject: [PATCH 23/55] Enable HTTP/2 between Cloudflared and Caddy --- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index c00bf7bb..821fba75 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -284,6 +284,11 @@ createConfig() { # Deactivate TLS verification for all services config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"noTLSVerify\": true}") + if bashio::var.true "${use_builtin_proxy}"; then + # Caddy allows HTTP/2 to work, so we set enable it for all services + config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"http2Origin\": true}") + fi + # Write content of config variable to config file for cloudflared bashio::jq "${config}" "." >"${default_config}" From 8a3211185be92c9506a22b1fe165f31132b0a2b1 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Jun 2025 00:08:48 -0300 Subject: [PATCH 24/55] Avoid using noTLSVerify for communication between Cloudflared and Caddy --- .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 8 +++--- cloudflared/rootfs/run.sh | 26 ++++++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 821fba75..c34daf36 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -281,12 +281,14 @@ createConfig() { config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http_status:404\"}]") fi - # Deactivate TLS verification for all services - config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"noTLSVerify\": true}") - if bashio::var.true "${use_builtin_proxy}"; then + # Caddy will generate a self-signed certificate, we can avoid noTLSVerify + config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"caPool\": \"/data/caddy/pki/authorities/local/root.crt\"}") # Caddy allows HTTP/2 to work, so we set enable it for all services config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"http2Origin\": true}") + else + # Deactivate TLS verification for all services + config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"noTLSVerify\": true}") fi # Write content of config variable to config file for cloudflared diff --git a/cloudflared/rootfs/run.sh b/cloudflared/rootfs/run.sh index c335bd9e..90f93c24 100755 --- a/cloudflared/rootfs/run.sh +++ b/cloudflared/rootfs/run.sh @@ -38,9 +38,33 @@ else options+=(run "$(bashio::config 'tunnel_name')") fi +function wait_for_file() { + local file="$1" + local timeout="$2" + local interval=1 + local elapsed=0 + + while [[ ! -f "${file}" && ${elapsed} -lt ${timeout} ]]; do + sleep "${interval}" + elapsed=$((elapsed + interval)) + done + + if [[ ! -f "${file}" ]]; then + bashio::exit.nok "Timed out waiting for ${file} to be created." + fi +} + if [[ ! -f /dev/shm/no_built_in_proxy ]]; then bashio::log.info "Waiting for Caddy to be ready..." - if ! curl --fail --silent --show-error --max-time 1 --retry 15 --retry-delay 1 --retry-connrefused --insecure https://healthcheck.localhost; then + wait_for_file /data/caddy/pki/authorities/local/root.crt 15 + if + curl --fail --silent --show-error --output /dev/null \ + --max-time 1 --retry 15 --retry-delay 1 --retry-connrefused \ + --cacert /data/caddy/pki/authorities/local/root.crt \ + https://healthcheck.localhost + then + bashio::log.info "Caddy is ready." + else bashio::exit.nok "Caddy did not become ready in time, aborting." fi fi From c265f15ded1dc272364ddf663227066ba410ee4d Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Jun 2025 00:12:21 -0300 Subject: [PATCH 25/55] Avoid unnecessary attempt to install root CA --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 162cd11c..c1f3d7ba 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -1,9 +1,11 @@ -{{ if not .auto_https }} { + # There is no need to attempt installing the root CA + skip_install_trust + {{ if not .auto_https }} # Disable automatic generation of Let's Encrypt certificates local_certs + {{ end }} } -{{ end }} # Allows to wait for Caddy to be ready before starting Cloudflared https://healthcheck.localhost { From dbb2c8b9dbd9a0bfd3c954958565174ec3b810eb Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Jun 2025 00:15:20 -0300 Subject: [PATCH 26/55] Disable persisting the generated json config --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index c1f3d7ba..527b90f4 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -1,4 +1,6 @@ { + # There is no need to persist the generate json configuration + persist_config off # There is no need to attempt installing the root CA skip_install_trust {{ if not .auto_https }} From c99fe1adf272d2a4097246ec9be893753d74204e Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Jun 2025 00:19:32 -0300 Subject: [PATCH 27/55] Disable unused admin API --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 527b90f4..6412ed8f 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -1,4 +1,6 @@ { + # We don't use the admin API + admin off # There is no need to persist the generate json configuration persist_config off # There is no need to attempt installing the root CA From 966ebf758e76b10f4da6dee51b6dcb1644387b23 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Jun 2025 00:25:03 -0300 Subject: [PATCH 28/55] Improve log format, including colors --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 6412ed8f..dc4d4302 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -9,6 +9,10 @@ # Disable automatic generation of Let's Encrypt certificates local_certs {{ end }} + log { + # More friendly logging format than the default json + format console + } } # Allows to wait for Caddy to be ready before starting Cloudflared From 2db2e9715bc47cc0643e432d752ff22b78204a57 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Jun 2025 00:39:57 -0300 Subject: [PATCH 29/55] Use HTTPS for catchall --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 8 ++++++-- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index dc4d4302..4aef327d 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -75,7 +75,11 @@ https://healthcheck.localhost { {{ end }} # Catch-all service for any unmatched requests -:80 { +https:// { + tls internal { + # Generate a self-signed certificate for any unmatched hostname + on_demand + } @cloudflared remote_ip 127.0.0.1 {{ if .catch_all_service }} # https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/#caddy @@ -103,7 +107,7 @@ https://healthcheck.localhost { {{ if .auto_https }} # Only used during automatic Let's Encrypt certificate generation -https://{{ .ha_external_hostname }}.localhost {{ range $i, $e := .additional_hosts }}https://{{ $e.hostname }}.localhost {{ end }} { +https://{{ .ha_external_hostname }}.localhost {{ range $i, $e := .additional_hosts }}https://{{ $e.hostname }}.localhost {{ end }} https://catchall.localhost { tls internal respond 407 } diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index c34daf36..ebf521c1 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -268,7 +268,7 @@ createConfig() { if bashio::var.true "${use_builtin_proxy}"; then bashio::log.info "Setting catch all service in Cloudflared to Caddy proxy" - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://127.0.0.1:80\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"https://catchall.localhost\"}]") elif bashio::config.true 'nginx_proxy_manager'; then bashio::log.warning "Runing with Nginxproxymanager support, make sure the add-on is installed and running." config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://a0d7b954-nginxproxymanager:80\"}]") @@ -401,6 +401,7 @@ configureCaddy() { bashio::log.info "Adding host entries for Cloudflared to communicate with Caddy..." echo "127.0.0.1 healthcheck.localhost" | tee -a /etc/hosts + echo "127.0.0.1 catchall.localhost" | tee -a /etc/hosts echo "127.0.0.1 ${external_hostname}.localhost" | tee -a /etc/hosts if bashio::config.has_value 'additional_hosts'; then for hostname in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do From df9734f583db90bd2b460db1eecdb49ebc8a3a9e Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Jun 2025 01:39:55 -0300 Subject: [PATCH 30/55] Update cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh --- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index ebf521c1..16756db0 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -285,6 +285,8 @@ createConfig() { # Caddy will generate a self-signed certificate, we can avoid noTLSVerify config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"caPool\": \"/data/caddy/pki/authorities/local/root.crt\"}") # Caddy allows HTTP/2 to work, so we set enable it for all services + # Even HTTP/3 is possible, but Cloudflared does not support it yet: + # https://developers.cloudflare.com/speed/optimization/protocol/http3/ config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"http2Origin\": true}") else # Deactivate TLS verification for all services From d91e8fb5a8018c0fb2bd54dd20922a15c347f0e1 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sat, 14 Jun 2025 20:47:11 -0300 Subject: [PATCH 31/55] Refactor tls on_demand for wildcard cert --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 87 ++++++++----------- .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 16 ++-- cloudflared/rootfs/run.sh | 2 +- 3 files changed, 43 insertions(+), 62 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 4aef327d..e9a474c2 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -15,16 +15,23 @@ } } -# Allows to wait for Caddy to be ready before starting Cloudflared -https://healthcheck.localhost { +# Used for communication between Cloudflared and Caddy +https://caddy.localhost { tls internal - respond "OK" 200 + respond 403 +} + +# Used for healthcheck to ensure Caddy is ready before starting Cloudflared +https://healthcheck.caddy.localhost { + tls internal + respond 200 } {{ .ha_external_hostname }} { @cloudflared remote_ip 127.0.0.1 - # https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/#caddy + reverse_proxy @cloudflared {{ .ha_service_url }} { + # https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/#caddy header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} {{ if hasPrefix "https://" .ha_service_url }} transport http { @@ -32,15 +39,12 @@ https://healthcheck.localhost { } {{ end }} } - {{ if hasPrefix "https://" .ha_service_url }} - reverse_proxy {{ .ha_service_url }} { + + reverse_proxy {{ .ha_service_url }} {{ if hasPrefix "https://" .ha_service_url }}{ transport http { tls_insecure_skip_verify } - } - {{ else }} - reverse_proxy {{ .ha_service_url }} - {{ end }} + }{{ end }} } {{ range $i, $e := .additional_hosts }} @@ -49,10 +53,9 @@ https://healthcheck.localhost { {{ if $e.internalOnly }} # Block connections from Cloudflared as service is internal only handle @cloudflared { - respond "This service can only be accessed from local network." 403 + respond 403 } {{ else }} - # https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/#caddy reverse_proxy @cloudflared {{ $e.service }} { header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} {{ if hasPrefix "https://" $e.service }} @@ -62,53 +65,37 @@ https://healthcheck.localhost { {{ end }} } {{ end }} - {{ if hasPrefix "https://" $e.service }} - reverse_proxy {{ $e.service }} { + reverse_proxy {{ $e.service }} {{ if hasPrefix "https://" $e.service }}{ transport http { tls_insecure_skip_verify } - } - {{ else }} - reverse_proxy {{ $e.service }} - {{ end }} + }{{ end }} } {{ end }} -# Catch-all service for any unmatched requests -https:// { - tls internal { - # Generate a self-signed certificate for any unmatched hostname - on_demand - } +# Catch-all service for any unmatched requests within the same base domain coming from Cloudflared +{{ $baseDomain := splitList "." .ha_external_hostname }} +{{ $baseDomain = slice $baseDomain (sub (len $baseDomain) 2) | join "." }} +https://*.{{ $baseDomain }} { + tls internal + @cloudflared remote_ip 127.0.0.1 - {{ if .catch_all_service }} - # https://developers.cloudflare.com/support/troubleshooting/restoring-visitor-ips/restoring-original-visitor-ips/#caddy - reverse_proxy @cloudflared {{ .catch_all_service }} { - header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} - {{ if hasPrefix "https://" .catch_all_service }} - transport http { - tls_insecure_skip_verify + handle @cloudflared { + {{ if .catch_all_service }} + reverse_proxy {{ .catch_all_service }} { + header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} + {{ if hasPrefix "https://" .catch_all_service }} + transport http { + tls_insecure_skip_verify + } + {{ end }} } + {{ else }} + respond 404 {{ end }} } - {{ if hasPrefix "https://" .catch_all_service }} - reverse_proxy {{ .catch_all_service }} { - transport http { - tls_insecure_skip_verify - } - } - {{ else }} - reverse_proxy {{ .catch_all_service }} - {{ end }} - {{ else }} - respond "This service was not found." 404 - {{ end }} -} -{{ if .auto_https }} -# Only used during automatic Let's Encrypt certificate generation -https://{{ .ha_external_hostname }}.localhost {{ range $i, $e := .additional_hosts }}https://{{ $e.hostname }}.localhost {{ end }} https://catchall.localhost { - tls internal - respond 407 + handle { + abort + } } -{{ end }} diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 16756db0..f5d6c91b 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -234,7 +234,7 @@ createConfig() { # Add Service for Home Assistant if 'external_hostname' is set if bashio::config.has_value 'external_hostname'; then if bashio::var.true "${use_builtin_proxy}"; then - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"https://${external_hostname}.localhost\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"https://caddy.localhost\"}]") else config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_service_url}\"}]") fi @@ -253,7 +253,7 @@ createConfig() { # Make Cloudflared always reach the Caddy proxy if enabled if bashio::var.true "${use_builtin_proxy}"; then - additional_host=$(bashio::jq "${additional_host}" '.service = "https://\(.hostname).localhost"') + additional_host=$(bashio::jq "${additional_host}" '.service = "https://caddy.localhost"') elif bashio::var.true "$(bashio::jq "${additional_host}" ".internalOnly")"; then bashio::exit.nok "'additional_hosts.internalOnly' is only supported when using the built-in Caddy proxy. Please set 'use_builtin_proxy' to true or remove 'internalOnly' from the additional host configuration." fi @@ -268,7 +268,7 @@ createConfig() { if bashio::var.true "${use_builtin_proxy}"; then bashio::log.info "Setting catch all service in Cloudflared to Caddy proxy" - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"https://catchall.localhost\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"https://caddy.localhost\"}]") elif bashio::config.true 'nginx_proxy_manager'; then bashio::log.warning "Runing with Nginxproxymanager support, make sure the add-on is installed and running." config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://a0d7b954-nginxproxymanager:80\"}]") @@ -402,14 +402,8 @@ configureCaddy() { caddy validate --config /etc/caddy/Caddyfile || bashio::exit.nok "Caddyfile validation failed, please check the logs above." bashio::log.info "Adding host entries for Cloudflared to communicate with Caddy..." - echo "127.0.0.1 healthcheck.localhost" | tee -a /etc/hosts - echo "127.0.0.1 catchall.localhost" | tee -a /etc/hosts - echo "127.0.0.1 ${external_hostname}.localhost" | tee -a /etc/hosts - if bashio::config.has_value 'additional_hosts'; then - for hostname in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do - echo "127.0.0.1 ${hostname}.localhost" | tee -a /etc/hosts - done - fi + echo "127.0.0.1 caddy.localhost" | tee -a /etc/hosts + echo "127.0.0.1 healthcheck.caddy.localhost" | tee -a /etc/hosts } # ============================================================================== diff --git a/cloudflared/rootfs/run.sh b/cloudflared/rootfs/run.sh index 90f93c24..ab60ac6c 100755 --- a/cloudflared/rootfs/run.sh +++ b/cloudflared/rootfs/run.sh @@ -61,7 +61,7 @@ if [[ ! -f /dev/shm/no_built_in_proxy ]]; then curl --fail --silent --show-error --output /dev/null \ --max-time 1 --retry 15 --retry-delay 1 --retry-connrefused \ --cacert /data/caddy/pki/authorities/local/root.crt \ - https://healthcheck.localhost + https://healthcheck.caddy.localhost then bashio::log.info "Caddy is ready." else From 107b5308972fdc201d4a8aafff32887d3685cc5e Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sun, 15 Jun 2025 02:02:46 -0300 Subject: [PATCH 32/55] Simplify caddy healthcheck --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 10 ++++------ .../rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 3 +-- cloudflared/rootfs/run.sh | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index e9a474c2..c07659c6 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -18,13 +18,11 @@ # Used for communication between Cloudflared and Caddy https://caddy.localhost { tls internal - respond 403 -} -# Used for healthcheck to ensure Caddy is ready before starting Cloudflared -https://healthcheck.caddy.localhost { - tls internal - respond 200 + # Used to ensure Caddy is ready before starting Cloudflared + respond /healthz 200 + + respond 403 } {{ .ha_external_hostname }} { diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index f5d6c91b..c7a040bc 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -401,9 +401,8 @@ configureCaddy() { caddy fmt --overwrite --config /etc/caddy/Caddyfile || bashio::exit.nok "Caddyfile formatting failed, please check the logs above." caddy validate --config /etc/caddy/Caddyfile || bashio::exit.nok "Caddyfile validation failed, please check the logs above." - bashio::log.info "Adding host entries for Cloudflared to communicate with Caddy..." + bashio::log.info "Adding host entry for communication between Cloudflared and Caddy..." echo "127.0.0.1 caddy.localhost" | tee -a /etc/hosts - echo "127.0.0.1 healthcheck.caddy.localhost" | tee -a /etc/hosts } # ============================================================================== diff --git a/cloudflared/rootfs/run.sh b/cloudflared/rootfs/run.sh index ab60ac6c..db0845c2 100755 --- a/cloudflared/rootfs/run.sh +++ b/cloudflared/rootfs/run.sh @@ -61,7 +61,7 @@ if [[ ! -f /dev/shm/no_built_in_proxy ]]; then curl --fail --silent --show-error --output /dev/null \ --max-time 1 --retry 15 --retry-delay 1 --retry-connrefused \ --cacert /data/caddy/pki/authorities/local/root.crt \ - https://healthcheck.caddy.localhost + https://caddy.localhost/healthz then bashio::log.info "Caddy is ready." else From c718e11995069d1865dfbdfacdd2cadc3747434d Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sun, 15 Jun 2025 02:09:50 -0300 Subject: [PATCH 33/55] Stop using Caddy for catch-all --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 27 ------------------- .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 13 +++------ 2 files changed, 4 insertions(+), 36 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index c07659c6..549ba5c2 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -70,30 +70,3 @@ https://caddy.localhost { }{{ end }} } {{ end }} - -# Catch-all service for any unmatched requests within the same base domain coming from Cloudflared -{{ $baseDomain := splitList "." .ha_external_hostname }} -{{ $baseDomain = slice $baseDomain (sub (len $baseDomain) 2) | join "." }} -https://*.{{ $baseDomain }} { - tls internal - - @cloudflared remote_ip 127.0.0.1 - handle @cloudflared { - {{ if .catch_all_service }} - reverse_proxy {{ .catch_all_service }} { - header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} - {{ if hasPrefix "https://" .catch_all_service }} - transport http { - tls_insecure_skip_verify - } - {{ end }} - } - {{ else }} - respond 404 - {{ end }} - } - - handle { - abort - } -} diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index c7a040bc..37bb1288 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -266,12 +266,9 @@ createConfig() { done <<<"$(jq -c '.additional_hosts[]' /data/options.json)" fi - if bashio::var.true "${use_builtin_proxy}"; then - bashio::log.info "Setting catch all service in Cloudflared to Caddy proxy" - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"https://caddy.localhost\"}]") - elif bashio::config.true 'nginx_proxy_manager'; then + if bashio::config.true 'nginx_proxy_manager'; then bashio::log.warning "Runing with Nginxproxymanager support, make sure the add-on is installed and running." - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://a0d7b954-nginxproxymanager:80\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://a0d7b954-nginxproxymanager\"}]") elif bashio::config.has_value 'catch_all_service'; then bashio::log.info "Runing with Catch all Service" # Setting catch all service to defined URL @@ -282,12 +279,10 @@ createConfig() { fi if bashio::var.true "${use_builtin_proxy}"; then - # Caddy will generate a self-signed certificate, we can avoid noTLSVerify - config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"caPool\": \"/data/caddy/pki/authorities/local/root.crt\"}") - # Caddy allows HTTP/2 to work, so we set enable it for all services + # With Caddy we can avoid noTLSVerify and also can use HTTP/2 # Even HTTP/3 is possible, but Cloudflared does not support it yet: # https://developers.cloudflare.com/speed/optimization/protocol/http3/ - config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"http2Origin\": true}") + config=$(bashio::jq "${config}" '(.ingress[] | select(.service == "https://caddy.localhost") | .originRequest) += {"caPool": "/data/caddy/pki/authorities/local/root.crt", "http2Origin": true}') else # Deactivate TLS verification for all services config=$(bashio::jq "${config}" ".ingress[].originRequest += {\"noTLSVerify\": true}") From 9bd4ca0c070d4ce25d6b9e714831d20467e1ad63 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sun, 15 Jun 2025 02:25:40 -0300 Subject: [PATCH 34/55] Cleanup some code --- .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 37bb1288..6abf910f 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -230,6 +230,7 @@ createConfig() { fi ha_service_url="${ha_service_protocol}://homeassistant:$(bashio::core.port)" + bashio::log.debug "ha_service_url: ${ha_service_url}" # Add Service for Home Assistant if 'external_hostname' is set if bashio::config.has_value 'external_hostname'; then @@ -266,16 +267,23 @@ createConfig() { done <<<"$(jq -c '.additional_hosts[]' /data/options.json)" fi + # Check if NGINX Proxy Manager is used to finalize configuration if bashio::config.true 'nginx_proxy_manager'; then + bashio::log.warning "Runing with Nginxproxymanager support, make sure the add-on is installed and running." config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://a0d7b954-nginxproxymanager\"}]") - elif bashio::config.has_value 'catch_all_service'; then - bashio::log.info "Runing with Catch all Service" - # Setting catch all service to defined URL - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"$(bashio::config 'catch_all_service')\"}]") else - # Finalize config without NPM support and catch all service, sending all other requests to HTTP:404 - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http_status:404\"}]") + + # Check if catch all service is defined + if bashio::config.has_value 'catch_all_service'; then + + bashio::log.info "Runing with Catch all Service" + # Setting catch all service to defined URL + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"$(bashio::config 'catch_all_service')\"}]") + else + # Finalize config without NPM support and catch all service, sending all other requests to HTTP:404 + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http_status:404\"}]") + fi fi if bashio::var.true "${use_builtin_proxy}"; then @@ -362,31 +370,20 @@ configureCaddy() { grep -q '^443$' then bashio::log.info "Internal port 443/tcp is exposed to host port 443, enabling automatic HTTPS" - auto_https=true + local auto_https=true else bashio::log.info "Internal port 443/tcp is not exposed to host port 443, not enabling automatic HTTPS" - auto_https=false - fi - - if bashio::config.true 'nginx_proxy_manager'; then - bashio::log.warning "Runing with Nginxproxymanager support, make sure the add-on is installed and running." - catch_all_service="http://a0d7b954-nginxproxymanager:80" - elif bashio::config.has_value 'catch_all_service'; then - bashio::log.info "Runing with Catch all Service" - catch_all_service="$(bashio::config 'catch_all_service')" - else - catch_all_service="" + local auto_https=false fi bashio::log.info "Generating Caddyfile..." tempio_input=$( jq -n \ + --argjson auto_https "${auto_https}" \ --arg ha_external_hostname "${external_hostname}" \ --arg ha_service_url "${ha_service_url}" \ - --arg catch_all_service "${catch_all_service}" \ --argjson additional_hosts "$(jq -c '.additional_hosts' /data/options.json)" \ - --argjson auto_https "${auto_https}" \ - '{ha_external_hostname: $ha_external_hostname, ha_service_url: $ha_service_url, catch_all_service: $catch_all_service, additional_hosts: $additional_hosts, auto_https: $auto_https}' + '{auto_https: $auto_https, ha_external_hostname: $ha_external_hostname, ha_service_url: $ha_service_url, additional_hosts: $additional_hosts}' ) bashio::log.debug "Tempio input:\n${tempio_input}" tempio -template /etc/caddy/Caddyfile.gtpl -out /etc/caddy/Caddyfile <<<"${tempio_input}" @@ -456,7 +453,7 @@ main() { if bashio::var.true "${use_builtin_proxy}"; then configureCaddy else - bashio::log.info "Using Cloudflared without built-in Caddy proxy" + bashio::log.info "Using Cloudflared without the built-in Caddy proxy" touch /dev/shm/no_built_in_proxy fi From 611bd1c929bbfb9621d9b67a6125416041faaae1 Mon Sep 17 00:00:00 2001 From: felipecrs Date: Fri, 4 Jul 2025 15:44:37 +0000 Subject: [PATCH 35/55] Prettified Code! --- cloudflared/DOCS.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index 2312fa5a..0ef8ffcd 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -235,7 +235,6 @@ Here is how you can leverage the built-in proxy for local access: 1. These additional add-on ports needs to be exposed through the add-on _Configuration_ page > _Network_: - - `80/tcp` for HTTP access - `443/tcp` for HTTPS access (this will also enable automatic HTTPS certificates and HTTP to HTTPS redirection) @@ -243,7 +242,6 @@ Here is how you can leverage the built-in proxy for local access: To expose them, click _Show disabled ports_ and repeat their port numbers in each of them: - - `80` for the `80/tcp` port - `443` for the `443/tcp` port - `443` for the `443/udp` port From e3a9ad0f40cca0c7136adafeac8b0010f6b25b6b Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sun, 6 Jul 2025 13:54:21 -0300 Subject: [PATCH 36/55] Prepare for remotely managed tunnels --- cloudflared/DOCS.md | 8 ++ .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 133 +++++++++++------- 2 files changed, 88 insertions(+), 53 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index 0ef8ffcd..08b17ec6 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -69,6 +69,14 @@ Trust Dashboard and provide the token to the add-on. Your tunnel should now be associated with the Cloudflared add-on. Any configuration changes should be made in the Cloudflare Teams dashboard. +If you would like to use the add-on built-in proxy, you should still set the +`external_hostname` option and optionally the `additional_hosts` option because +the built-in proxy needs to know the domain names to serve. + +In your remotely managed tunnel, you can then set the service URL to +`https://caddy.localhost` if you wish to forward requests to the built-in +proxy. + ## Configuration **These configuration options only apply to the local tunnel setup**. More diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 6abf910f..53d7fbb8 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -68,6 +68,55 @@ checkConfig() { fi } +# ------------------------------------------------------------------------------ +# Sets global variables used in the script +# ------------------------------------------------------------------------------ +setGlobalVars() { + bashio::log.trace "${FUNCNAME[0]}" + + default_config="/tmp/config.json" + tunnel_uuid="" + data_path="/data" + + bashio::log.debug "Checking if SSL is used for Home Assistant..." + local ha_protocol + if bashio::var.true "$(bashio::core.ssl)"; then + ha_protocol="https" + else + ha_protocol="http" + fi + bashio::log.debug "ha_protocol: ${ha_protocol}" + + bashio::log.debug "Checking port used for Home Assistant..." + local ha_port + ha_port="$(bashio::core.port)" + bashio::log.debug "ha_port: ${ha_port}" + + ha_url="${ha_protocol}://homeassistant:${ha_port}" + bashio::log.debug "ha_url: ${ha_url}" + + if bashio::config.has_value 'external_hostname'; then + external_hostname="$(bashio::config 'external_hostname')" + else + external_hostname="" + fi + bashio::log.debug "external_hostname: ${external_hostname}" + + if bashio::config.has_value 'tunnel_name'; then + tunnel_name="$(bashio::config 'tunnel_name')" + else + tunnel_name="homeassistant" + fi + bashio::log.debug "tunnel_name: ${tunnel_name}" + + if bashio::config.true 'use_builtin_proxy'; then + use_builtin_proxy=true + else + use_builtin_proxy=false + fi + bashio::log.debug "use_builtin_proxy: ${use_builtin_proxy}" +} + # ------------------------------------------------------------------------------ # Checks if Cloudflare services are reachable # ------------------------------------------------------------------------------ @@ -208,7 +257,6 @@ createTunnel() { # Create Cloudflare config with variables from HA-Add-on-Config # ------------------------------------------------------------------------------ createConfig() { - local ha_service_protocol local config bashio::log.trace "${FUNCNAME[0]}" bashio::log.info "Creating config file..." @@ -217,27 +265,12 @@ createConfig() { config=$(bashio::jq "{\"tunnel\":\"${tunnel_uuid}\"}" ".") config=$(bashio::jq "${config}" ".\"credentials-file\" += \"${data_path}/tunnel.json\"") - bashio::log.debug "Checking if SSL is used..." - if bashio::var.true "$(bashio::core.ssl)"; then - ha_service_protocol="https" - else - ha_service_protocol="http" - fi - bashio::log.debug "ha_service_protocol: ${ha_service_protocol}" - - if bashio::var.is_empty "${ha_service_protocol}"; then - bashio::exit.nok "Error checking if SSL is enabled" - fi - - ha_service_url="${ha_service_protocol}://homeassistant:$(bashio::core.port)" - bashio::log.debug "ha_service_url: ${ha_service_url}" - # Add Service for Home Assistant if 'external_hostname' is set - if bashio::config.has_value 'external_hostname'; then + if bashio::var.has_value "${external_hostname}"; then if bashio::var.true "${use_builtin_proxy}"; then config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"https://caddy.localhost\"}]") else - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_service_url}\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_url}\"}]") fi fi @@ -325,9 +358,6 @@ createDNS() { if bashio::config.has_value 'additional_hosts'; then for host in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do bashio::log.info "Creating DNS entry ${host}..." - if bashio::var.is_empty "${host}"; then - bashio::exit.nok "'hostname' in 'additional_hosts' is empty, please enter a valid String" - fi cloudflared --origincert="${data_path}/cert.pem" tunnel --loglevel "${CLOUDFLARED_LOG}" route dns -f "${tunnel_uuid}" "${host}" || bashio::exit.nok "Failed to create DNS entry ${host}." done @@ -358,7 +388,24 @@ setCloudflaredLogLevel() { } +# ------------------------------------------------------------------------------ +# Configure the built-in Caddy proxy +# ------------------------------------------------------------------------------ configureCaddy() { + bashio::log.trace "${FUNCNAME[0]}" + + if bashio::var.false "${use_builtin_proxy}"; then + bashio::log.info "Using Cloudflared without the built-in Caddy proxy" + touch /dev/shm/no_built_in_proxy + return "${__BASHIO_EXIT_OK}" + fi + + if bashio::var.is_empty "${external_hostname}"; then + bashio::log.warning "Using Cloudflared without the built-in Caddy proxy because 'external_hostname' is not set." + touch /dev/shm/no_built_in_proxy + return "${__BASHIO_EXIT_OK}" + fi + bashio::log.info "Configuring built-in Caddy proxy..." if @@ -369,23 +416,24 @@ configureCaddy() { jq --exit-status --raw-output '.data.network["443/tcp"]' | grep -q '^443$' then - bashio::log.info "Internal port 443/tcp is exposed to host port 443, enabling automatic HTTPS" + bashio::log.info "Internal port 443/tcp is exposed to host port 443, enabling automatic HTTPS for local proxy" local auto_https=true else - bashio::log.info "Internal port 443/tcp is not exposed to host port 443, not enabling automatic HTTPS" + bashio::log.info "Internal port 443/tcp is not exposed to host port 443, not enabling automatic HTTPS for local proxy" local auto_https=false fi bashio::log.info "Generating Caddyfile..." + additional_hosts=$(bashio::jq "/data/options.json" ".additional_hosts") tempio_input=$( jq -n \ --argjson auto_https "${auto_https}" \ --arg ha_external_hostname "${external_hostname}" \ - --arg ha_service_url "${ha_service_url}" \ - --argjson additional_hosts "$(jq -c '.additional_hosts' /data/options.json)" \ + --arg ha_service_url "${ha_url}" \ + --argjson additional_hosts "${additional_hosts}" \ '{auto_https: $auto_https, ha_external_hostname: $ha_external_hostname, ha_service_url: $ha_service_url, additional_hosts: $additional_hosts}' ) - bashio::log.debug "Tempio input:\n${tempio_input}" + bashio::log.debug "Tempio input for generating Caddyfile:\n${tempio_input}" tempio -template /etc/caddy/Caddyfile.gtpl -out /etc/caddy/Caddyfile <<<"${tempio_input}" bashio::log.debug "Generated Caddyfile:\n$(cat /etc/caddy/Caddyfile)" @@ -400,15 +448,15 @@ configureCaddy() { # ============================================================================== # RUN LOGIC # ------------------------------------------------------------------------------ -declare default_config=/tmp/config.json -external_hostname="" -tunnel_name="homeassistant" -tunnel_uuid="" -data_path="/data" - main() { bashio::log.trace "${FUNCNAME[0]}" + checkConfig + + setGlobalVars + + configureCaddy + setCloudflaredLogLevel # Run connectivity checks if debug mode activated @@ -424,20 +472,6 @@ main() { bashio::exit.ok fi - checkConfig - - if bashio::config.has_value 'tunnel_name'; then - tunnel_name="$(bashio::config 'tunnel_name')" - fi - - external_hostname="$(bashio::config 'external_hostname')" - - if bashio::config.true 'use_builtin_proxy'; then - use_builtin_proxy=true - else - use_builtin_proxy=false - fi - if ! hasCertificate; then createCertificate fi @@ -450,13 +484,6 @@ main() { createDNS - if bashio::var.true "${use_builtin_proxy}"; then - configureCaddy - else - bashio::log.info "Using Cloudflared without the built-in Caddy proxy" - touch /dev/shm/no_built_in_proxy - fi - bashio::log.info "Finished setting up the Cloudflare Tunnel" } main "$@" From c6536290066437290aeef4f96adce550ea6e1565 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sun, 6 Jul 2025 14:20:06 -0300 Subject: [PATCH 37/55] Use bashio to get forwarded addon port 443 --- .../rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 53d7fbb8..5dd82416 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -86,7 +86,7 @@ setGlobalVars() { ha_protocol="http" fi bashio::log.debug "ha_protocol: ${ha_protocol}" - + bashio::log.debug "Checking port used for Home Assistant..." local ha_port ha_port="$(bashio::core.port)" @@ -408,14 +408,7 @@ configureCaddy() { bashio::log.info "Configuring built-in Caddy proxy..." - if - curl -fsSL \ - -H "Authorization: Bearer ${SUPERVISOR_TOKEN}" \ - -H "Content-Type: application/json" \ - http://supervisor/addons/self/info | - jq --exit-status --raw-output '.data.network["443/tcp"]' | - grep -q '^443$' - then + if [[ "$(bashio::addon.port "443/tcp")" == "443" ]]; then bashio::log.info "Internal port 443/tcp is exposed to host port 443, enabling automatic HTTPS for local proxy" local auto_https=true else From c0a721c838d62654160474db497e86ae5af96248 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Fri, 22 Aug 2025 13:40:11 -0300 Subject: [PATCH 38/55] Update Caddy to 2.10.1 --- cloudflared/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudflared/Dockerfile b/cloudflared/Dockerfile index 20a9d207..05912bb6 100644 --- a/cloudflared/Dockerfile +++ b/cloudflared/Dockerfile @@ -9,7 +9,7 @@ ARG BUILD_ARCH="amd64" # renovate: datasource=repology depName=yq packageName=alpine_3_22/yq-go versioning=loose ARG YQ_VERSION="4.46.1-r1" # renovate: datasource=github-releases depName=caddy packageName=caddyserver/caddy -ARG CADDY_VERSION="2.10.0" +ARG CADDY_VERSION="2.10.1" # renovate: datasource=github-releases depName=cloudflared packageName=cloudflare/cloudflared versioning=loose ARG CLOUDFLARED_VERSION="2025.8.1" From f0a9d60012a01672262a9a087585e6dccbdd4eae Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Tue, 26 Aug 2025 12:09:25 -0300 Subject: [PATCH 39/55] Implement s6-overlay native readiness check for caddy service --- .../s6-overlay/s6-rc.d/caddy/check_readiness.sh | 5 +++++ .../etc/s6-overlay/s6-rc.d/caddy/notification-fd | 1 + .../rootfs/etc/s6-overlay/s6-rc.d/caddy/run | 3 ++- .../etc/s6-overlay/s6-rc.d/caddy/timeout-kill | 1 + .../etc/s6-overlay/s6-rc.d/caddy/timeout-up | 1 + cloudflared/rootfs/run.sh | 15 --------------- 6 files changed, 10 insertions(+), 16 deletions(-) create mode 100755 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/check_readiness.sh create mode 100644 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/notification-fd create mode 100644 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/timeout-kill create mode 100644 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/timeout-up diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/check_readiness.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/check_readiness.sh new file mode 100755 index 00000000..80ec999c --- /dev/null +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/check_readiness.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +exec curl --fail --silent --output /dev/null --max-time 1 \ + --cacert /data/caddy/pki/authorities/local/root.crt \ + https://caddy.localhost/healthz diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/notification-fd b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/notification-fd new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/notification-fd @@ -0,0 +1 @@ +3 diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run index 6157377b..e36594ce 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run @@ -8,4 +8,5 @@ if [[ -f /dev/shm/no_built_in_proxy ]]; then fi bashio::log.info "Starting Caddy..." -exec env XDG_DATA_HOME=/data caddy run --config /etc/caddy/Caddyfile +exec s6-notifyoncheck -c /etc/s6-overlay/s6-rc.d/caddy/check_readiness.sh \ + env XDG_DATA_HOME=/data caddy run --config /etc/caddy/Caddyfile diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/timeout-kill b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/timeout-kill new file mode 100644 index 00000000..9e703691 --- /dev/null +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/timeout-kill @@ -0,0 +1 @@ +15000 diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/timeout-up b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/timeout-up new file mode 100644 index 00000000..9e703691 --- /dev/null +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/timeout-up @@ -0,0 +1 @@ +15000 diff --git a/cloudflared/rootfs/run.sh b/cloudflared/rootfs/run.sh index db0845c2..ab11666a 100755 --- a/cloudflared/rootfs/run.sh +++ b/cloudflared/rootfs/run.sh @@ -54,21 +54,6 @@ function wait_for_file() { fi } -if [[ ! -f /dev/shm/no_built_in_proxy ]]; then - bashio::log.info "Waiting for Caddy to be ready..." - wait_for_file /data/caddy/pki/authorities/local/root.crt 15 - if - curl --fail --silent --show-error --output /dev/null \ - --max-time 1 --retry 15 --retry-delay 1 --retry-connrefused \ - --cacert /data/caddy/pki/authorities/local/root.crt \ - https://caddy.localhost/healthz - then - bashio::log.info "Caddy is ready." - else - bashio::exit.nok "Caddy did not become ready in time, aborting." - fi -fi - bashio::log.info "Connecting Cloudflare Tunnel..." bashio::log.debug "cloudflared tunnel ${options[*]}" exec cloudflared tunnel "${options[@]}" From e5e40d719f549ce35fbd3e5d0b53fec9bf5917ec Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Tue, 26 Aug 2025 12:09:35 -0300 Subject: [PATCH 40/55] Update Caddy to 2.10.2 --- cloudflared/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudflared/Dockerfile b/cloudflared/Dockerfile index 05912bb6..2484b723 100644 --- a/cloudflared/Dockerfile +++ b/cloudflared/Dockerfile @@ -9,7 +9,7 @@ ARG BUILD_ARCH="amd64" # renovate: datasource=repology depName=yq packageName=alpine_3_22/yq-go versioning=loose ARG YQ_VERSION="4.46.1-r1" # renovate: datasource=github-releases depName=caddy packageName=caddyserver/caddy -ARG CADDY_VERSION="2.10.1" +ARG CADDY_VERSION="2.10.2" # renovate: datasource=github-releases depName=cloudflared packageName=cloudflare/cloudflared versioning=loose ARG CLOUDFLARED_VERSION="2025.8.1" From 46c3f37c2dbf248aaad1235d84bf38c925080a1a Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 24 Sep 2025 16:07:26 +0200 Subject: [PATCH 41/55] Translations: replace Nginx with Caddy --- cloudflared/translations/de.yaml | 4 ++-- cloudflared/translations/fr.yaml | 4 ++-- cloudflared/translations/he.yaml | 4 ++-- cloudflared/translations/nl.yaml | 4 ++-- cloudflared/translations/pl.yaml | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cloudflared/translations/de.yaml b/cloudflared/translations/de.yaml index a6e54d31..e5133921 100644 --- a/cloudflared/translations/de.yaml +++ b/cloudflared/translations/de.yaml @@ -39,9 +39,9 @@ configuration: description: >- Setzt das "Nginx-Proxy-Manager Add-on" als Catch-All-Dienst. use_builtin_proxy: - name: Eingebauten Nginx proxy verwenden + name: Eingebauten Caddy proxy verwenden description: >- - Die Verbindung zu Home Assistant wird über den eingebauten Nginx-Proxy + Die Verbindung zu Home Assistant wird über den eingebauten Caddy-Proxy hergestellt. (Workaround für Probleme mit den Live Logs). Diese Option ist standardmäßig aktiviert. tunnel_token: diff --git a/cloudflared/translations/fr.yaml b/cloudflared/translations/fr.yaml index 3ef339d2..0a741f02 100644 --- a/cloudflared/translations/fr.yaml +++ b/cloudflared/translations/fr.yaml @@ -39,9 +39,9 @@ configuration: description: >- Définir le service Catch-All sur le module complémentaire "Nginx-Proxy-Manager Community Add-Ons". use_builtin_proxy: - name: Utiliser le proxy Nginx intégré + name: Utiliser le proxy Caddy intégré description: >- - La connexion à Home Assistant sera établie via le proxy Nginx intégré. + La connexion à Home Assistant sera établie via le proxy Caddy intégré. (Solution de contournement pour les problèmes avec les journaux en direct). Cette option est activée par défaut. tunnel_token: diff --git a/cloudflared/translations/he.yaml b/cloudflared/translations/he.yaml index 3f5a0ed3..a427c21a 100644 --- a/cloudflared/translations/he.yaml +++ b/cloudflared/translations/he.yaml @@ -37,9 +37,9 @@ configuration: description: >- מגדיר את שירות catch-all להרחבה "Nginx-Proxy-Manager Community Add-ons". use_builtin_proxy: - name: השתמש ב-Nginx proxy המובנה + name: השתמש ב-Caddy proxy המובנה description: >- - החיבור ל-Home Assistant יתבצע דרך ה-Nginx proxy המובנה. + החיבור ל-Home Assistant יתבצע דרך ה-Caddy proxy המובנה. (פתרון בעיות עבור בעיות עם יומני חיים). אפשרות זו מופעלת כברירת מחדל. tunnel_token: diff --git a/cloudflared/translations/nl.yaml b/cloudflared/translations/nl.yaml index 9a4090e1..5f1f86d6 100644 --- a/cloudflared/translations/nl.yaml +++ b/cloudflared/translations/nl.yaml @@ -40,10 +40,10 @@ configuration: Gebruikt de "Nginx-Proxy-Manager Community Add-Ons" add-on als de catch-all dienst. use_builtin_proxy: - name: Gebruik ingebouwde Nginx proxy + name: Gebruik ingebouwde Caddy proxy description: >- De verbinding met Home Assistant wordt gemaakt via de ingebouwde - Nginx proxy. (Workaround voor problemen met live logs). + Caddy proxy. (Workaround voor problemen met live logs). Deze optie is standaard ingeschakeld. tunnel_token: name: Cloudflare Tunnel Token diff --git a/cloudflared/translations/pl.yaml b/cloudflared/translations/pl.yaml index ef809585..e0b779b3 100644 --- a/cloudflared/translations/pl.yaml +++ b/cloudflared/translations/pl.yaml @@ -40,10 +40,10 @@ configuration: Ustawia usługę catch-all na dodatek "Nginx-Proxy-Manager Community Add-Ons" use_builtin_proxy: - name: Użyj wbudowanego proxy Nginx + name: Użyj wbudowanego proxy Caddy description: >- Połączenie z Home Assistant będzie realizowane przez wbudowane - proxy Nginx. (Obejście problemów z logami na żywo). + proxy Caddy. (Obejście problemów z logami na żywo). Ta opcja jest domyślnie włączona. tunnel_token: name: Token Tunelu Cloudflare From 114cf56a021f8d90982f677c743412103eb2600e Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 29 Sep 2025 19:58:09 -0300 Subject: [PATCH 42/55] Add checks to prevent startup with invalid use_builtin_proxy settings --- .../rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 9a5cf4ec..f13a9927 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -66,6 +66,16 @@ checkConfig() { if bashio::config.has_value 'catch_all_service' && bashio::config.true 'nginx_proxy_manager'; then bashio::exit.nok "The config includes 'nginx_proxy_manager' and 'catch_all_service'. Please delete one of them since they are mutually exclusive" fi + + # Check if 'use_builtin_proxy' and 'tunnel_token' are both included in config. + if bashio::config.true 'use_builtin_proxy' && bashio::config.has_value 'tunnel_token'; then + bashio::exit.nok "'use_builtin_proxy' cannot be used together with 'tunnel_token'. Please remove one of them from the configuration" + fi + + # Check if 'use_builtin_proxy' is true and 'external_hostname' is empty + if bashio::config.true 'use_builtin_proxy' && bashio::config.is_empty 'external_hostname'; then + bashio::exit.nok "'use_builtin_proxy' can only be used if 'external_hostname' is set. Please set 'external_hostname' or disable 'use_builtin_proxy'" + fi } # ------------------------------------------------------------------------------ From 30326ebc715f9c6f0d5da826fd25df0b2e20d76b Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 29 Sep 2025 20:12:04 -0300 Subject: [PATCH 43/55] Update use_builtin_proxy docs and disable it by default --- cloudflared/DOCS.md | 9 ++++----- cloudflared/config.yaml | 1 + cloudflared/translations/de.yaml | 8 +++++--- cloudflared/translations/en.yaml | 8 ++++---- cloudflared/translations/fr.yaml | 8 +++++--- cloudflared/translations/he.yaml | 7 ++++--- cloudflared/translations/nl.yaml | 8 +++++--- cloudflared/translations/pl.yaml | 8 +++++--- 8 files changed, 33 insertions(+), 24 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index c199593b..755c2585 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -232,13 +232,12 @@ them to wherever you like. ### Option: `use_builtin_proxy` If enabled, the connection to Home Assistant and additional hosts will be made -through the built-in Caddy proxy. This works around issues with live logs ([#744](https://github.com/brenner-tobias/addon-cloudflared/discussions/744)) -and allows a unified access to Home Assistant and additional hosts even within -your local network. +through the built-in Caddy proxy. This allows a unified access to Home +Assistant and additional hosts even within your local network. -**Note**: _This option is enabled by default._ +**Note**: _This option is disabled by default._ -Here is how you can leverage the built-in proxy for local access: +Here is how you can leverage the built-in Caddy proxy for local access: 1. These additional add-on ports needs to be exposed through the add-on _Configuration_ page > _Network_: diff --git a/cloudflared/config.yaml b/cloudflared/config.yaml index ce9126e8..5a4a9464 100644 --- a/cloudflared/config.yaml +++ b/cloudflared/config.yaml @@ -39,6 +39,7 @@ schema: tunnel_name: str? catch_all_service: str? nginx_proxy_manager: bool? + use_builtin_proxy: bool? tunnel_token: str? post_quantum: bool? run_parameters: diff --git a/cloudflared/translations/de.yaml b/cloudflared/translations/de.yaml index e5133921..bca660ae 100644 --- a/cloudflared/translations/de.yaml +++ b/cloudflared/translations/de.yaml @@ -41,9 +41,11 @@ configuration: use_builtin_proxy: name: Eingebauten Caddy proxy verwenden description: >- - Die Verbindung zu Home Assistant wird über den eingebauten Caddy-Proxy - hergestellt. (Workaround für Probleme mit den Live Logs). - Diese Option ist standardmäßig aktiviert. + Die Verbindung zu Home Assistant und zusätzlichen Hosts wird über den + eingebauten Caddy-Proxy hergestellt. Dies ermöglicht einen einheitlichen + Zugang zu Home Assistant und zusätzlichen Hosts auch innerhalb Ihres + lokalen Netzwerks. Lesen Sie die Dokumentation für weitere Details. + Diese Option ist standardmäßig deaktiviert. tunnel_token: name: Cloudflare Tunnel Token description: >- diff --git a/cloudflared/translations/en.yaml b/cloudflared/translations/en.yaml index c93771e2..611fd10e 100644 --- a/cloudflared/translations/en.yaml +++ b/cloudflared/translations/en.yaml @@ -43,10 +43,10 @@ configuration: name: Use built-in Caddy proxy description: >- The connection to Home Assistant and additional hosts will be made - through the built-in Caddy proxy. This works around issues with live logs - and allows an unified access to Home Assistant and additional hosts even - within your local network, read the documentation for more details. - This option is enabled by default. + through the built-in Caddy proxy. This allows a unified access to Home + Assistant and additional hosts even within your local network. Read the + documentation for more details. + This option is disabled by default. tunnel_token: name: Cloudflare Tunnel Token description: >- diff --git a/cloudflared/translations/fr.yaml b/cloudflared/translations/fr.yaml index 0a741f02..91bc6d6a 100644 --- a/cloudflared/translations/fr.yaml +++ b/cloudflared/translations/fr.yaml @@ -41,9 +41,11 @@ configuration: use_builtin_proxy: name: Utiliser le proxy Caddy intégré description: >- - La connexion à Home Assistant sera établie via le proxy Caddy intégré. - (Solution de contournement pour les problèmes avec les journaux en direct). - Cette option est activée par défaut. + La connexion à Home Assistant et aux hôtes supplémentaires sera établie + via le proxy Caddy intégré. Cela permet un accès unifié à Home Assistant + et aux hôtes supplémentaires même au sein de votre réseau local. Lisez + la documentation pour plus de détails. + Cette option est désactivée par défaut. tunnel_token: name: Token du tunnel Cloudflare description: >- diff --git a/cloudflared/translations/he.yaml b/cloudflared/translations/he.yaml index a427c21a..e0104c9a 100644 --- a/cloudflared/translations/he.yaml +++ b/cloudflared/translations/he.yaml @@ -39,9 +39,10 @@ configuration: use_builtin_proxy: name: השתמש ב-Caddy proxy המובנה description: >- - החיבור ל-Home Assistant יתבצע דרך ה-Caddy proxy המובנה. - (פתרון בעיות עבור בעיות עם יומני חיים). - אפשרות זו מופעלת כברירת מחדל. + החיבור ל-Home Assistant ומארחים נוספים יתבצע דרך ה-Caddy proxy המובנה. + זה מאפשר גישה מאוחדת ל-Home Assistant ומארחים נוספים גם בתוך הרשת + המקומית שלך. קרא את התיעוד לפרטים נוספים. + אפשרות זו מושבתת כברירת מחדל. tunnel_token: name: אסימון מנהרת Cloudflare description: >- diff --git a/cloudflared/translations/nl.yaml b/cloudflared/translations/nl.yaml index 5f1f86d6..89a48280 100644 --- a/cloudflared/translations/nl.yaml +++ b/cloudflared/translations/nl.yaml @@ -42,9 +42,11 @@ configuration: use_builtin_proxy: name: Gebruik ingebouwde Caddy proxy description: >- - De verbinding met Home Assistant wordt gemaakt via de ingebouwde - Caddy proxy. (Workaround voor problemen met live logs). - Deze optie is standaard ingeschakeld. + De verbinding met Home Assistant en aanvullende hosts wordt gemaakt via + de ingebouwde Caddy proxy. Dit maakt een uniforme toegang tot Home + Assistant en aanvullende hosts mogelijk, zelfs binnen je lokale netwerk. + Lees de documentatie voor meer details. + Deze optie is standaard uitgeschakeld. tunnel_token: name: Cloudflare Tunnel Token description: >- diff --git a/cloudflared/translations/pl.yaml b/cloudflared/translations/pl.yaml index e0b779b3..216a8457 100644 --- a/cloudflared/translations/pl.yaml +++ b/cloudflared/translations/pl.yaml @@ -42,9 +42,11 @@ configuration: use_builtin_proxy: name: Użyj wbudowanego proxy Caddy description: >- - Połączenie z Home Assistant będzie realizowane przez wbudowane - proxy Caddy. (Obejście problemów z logami na żywo). - Ta opcja jest domyślnie włączona. + Połączenie z Home Assistant i dodatkowymi hostami będzie realizowane + przez wbudowane proxy Caddy. Umożliwia to jednolity dostęp do Home + Assistant i dodatkowych hostów nawet w sieci lokalnej. Przeczytaj + dokumentację aby uzyskać więcej szczegółów. + Ta opcja jest domyślnie wyłączona. tunnel_token: name: Token Tunelu Cloudflare description: >- From fdf185cfedc31d745861d66534a42d6295dfdb35 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 29 Sep 2025 20:16:57 -0300 Subject: [PATCH 44/55] Remove unnecessary check and fix tunnel_token check --- .../rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index f13a9927..dd8bbee7 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -18,7 +18,8 @@ checkConfig() { # Check for minimum configuration options if - bashio::config.is_empty 'external_hostname' && + bashio::config.is_empty 'tunnel_token' && + bashio::config.is_empty 'external_hostname' && bashio::config.is_empty 'additional_hosts' && bashio::config.is_empty 'catch_all_service' && bashio::config.is_empty 'nginx_proxy_manager' @@ -67,11 +68,6 @@ checkConfig() { bashio::exit.nok "The config includes 'nginx_proxy_manager' and 'catch_all_service'. Please delete one of them since they are mutually exclusive" fi - # Check if 'use_builtin_proxy' and 'tunnel_token' are both included in config. - if bashio::config.true 'use_builtin_proxy' && bashio::config.has_value 'tunnel_token'; then - bashio::exit.nok "'use_builtin_proxy' cannot be used together with 'tunnel_token'. Please remove one of them from the configuration" - fi - # Check if 'use_builtin_proxy' is true and 'external_hostname' is empty if bashio::config.true 'use_builtin_proxy' && bashio::config.is_empty 'external_hostname'; then bashio::exit.nok "'use_builtin_proxy' can only be used if 'external_hostname' is set. Please set 'external_hostname' or disable 'use_builtin_proxy'" @@ -418,12 +414,6 @@ configureCaddy() { return "${__BASHIO_EXIT_OK}" fi - if bashio::var.is_empty "${external_hostname}"; then - bashio::log.warning "Using Cloudflared without the built-in Caddy proxy because 'external_hostname' is not set." - touch /dev/shm/no_built_in_proxy - return "${__BASHIO_EXIT_OK}" - fi - bashio::log.info "Configuring built-in Caddy proxy..." if [[ "$(bashio::addon.port "443/tcp")" == "443" ]]; then From fc94a2ff23e7b9a692429c85e5a991e65f2c5ec8 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 29 Sep 2025 20:19:59 -0300 Subject: [PATCH 45/55] Fix S6 starting Caddy if tunnel_token is set --- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish | 4 ++-- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run | 2 +- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish index e500648a..659c06c8 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish @@ -5,8 +5,8 @@ # Take down the S6 supervision tree when Caddy fails # ============================================================================== -# Avoid halting container if the built-in proxy was signaled as disabled -if [[ -f /dev/shm/no_built_in_proxy ]]; then +# Avoid halting container if the built-in proxy was not enabled +if [[ ! -f /dev/shm/use_built_in_proxy ]]; then exit 0 fi diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run index e36594ce..ff81324c 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run @@ -1,7 +1,7 @@ #!/command/with-contenv bashio # shellcheck shell=bash -if [[ -f /dev/shm/no_built_in_proxy ]]; then +if [[ ! -f /dev/shm/use_built_in_proxy ]]; then # Tell S6-Overlay not to restart this service s6-svc -O . exit 0 diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index dd8bbee7..8958e3c7 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -410,7 +410,6 @@ configureCaddy() { if bashio::var.false "${use_builtin_proxy}"; then bashio::log.info "Using Cloudflared without the built-in Caddy proxy" - touch /dev/shm/no_built_in_proxy return "${__BASHIO_EXIT_OK}" fi @@ -444,6 +443,9 @@ configureCaddy() { bashio::log.info "Adding host entry for communication between Cloudflared and Caddy..." echo "127.0.0.1 caddy.localhost" | tee -a /etc/hosts + + # Signal Caddy service to run + touch /dev/shm/use_built_in_proxy } # ============================================================================== From a0522f33536b25903874f40b70879a8b185976a3 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 29 Sep 2025 20:25:51 -0300 Subject: [PATCH 46/55] Add translations for new network ports --- cloudflared/translations/de.yaml | 5 ++++- cloudflared/translations/fr.yaml | 5 ++++- cloudflared/translations/he.yaml | 5 ++++- cloudflared/translations/nl.yaml | 5 ++++- cloudflared/translations/pl.yaml | 5 ++++- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/cloudflared/translations/de.yaml b/cloudflared/translations/de.yaml index bca660ae..945b7a52 100644 --- a/cloudflared/translations/de.yaml +++ b/cloudflared/translations/de.yaml @@ -53,4 +53,7 @@ configuration: Wird verwendet, wenn der Tunnel mit dem Cloudflare Dashboard eingerichtet wird. network: - 36500/tcp: Web-Interface für Metriken (36500/tcp) + 36500/tcp: Metriken-Web-Interface + 80/tcp: Eingebaute Caddy-Proxy-HTTP-Schnittstelle + 443/tcp: Eingebaute Caddy-Proxy-HTTPS-Schnittstelle + 443/udp: Eingebaute Caddy-Proxy-HTTP/3-QUIC-Schnittstelle diff --git a/cloudflared/translations/fr.yaml b/cloudflared/translations/fr.yaml index 91bc6d6a..bdec65a5 100644 --- a/cloudflared/translations/fr.yaml +++ b/cloudflared/translations/fr.yaml @@ -52,4 +52,7 @@ configuration: Lorsque cette option est définie, toutes les autres options seront ignorées. Utilisez cette option si vous avez configuré le tunnel via le tableau de bord Cloudflare. network: - 36500/tcp: Interface web des métriques (36500/tcp) + 36500/tcp: Interface Web des Métriques + 80/tcp: Interface HTTP du Proxy Caddy Intégré + 443/tcp: Interface HTTPS du Proxy Caddy Intégré + 443/udp: Interface HTTP/3 QUIC du Proxy Caddy Intégré diff --git a/cloudflared/translations/he.yaml b/cloudflared/translations/he.yaml index e0104c9a..08d33757 100644 --- a/cloudflared/translations/he.yaml +++ b/cloudflared/translations/he.yaml @@ -49,4 +49,7 @@ configuration: כאשר מוגדר, כל האפשרויות האחרות יתעלמו. יש להשתמש באפשרות זו בהגדרת המנהרה עם לוח המחוונים של Cloudflare. network: - 36500/tcp: ממשק אינטרנט למדדים (36500/tcp) + 36500/tcp: ממשק אינטרנט למדדים + 80/tcp: ממשק HTTP של Caddy Proxy המובנה + 443/tcp: ממשק HTTPS של Caddy Proxy המובנה + 443/udp: ממשק HTTP/3 QUIC של Caddy Proxy המובנה diff --git a/cloudflared/translations/nl.yaml b/cloudflared/translations/nl.yaml index 89a48280..4e223c2e 100644 --- a/cloudflared/translations/nl.yaml +++ b/cloudflared/translations/nl.yaml @@ -54,4 +54,7 @@ configuration: Gebruik deze optie als je de tunel met het Cloudflare Dashboard instelt. network: - 36500/tcp: Webinterface voor statistieken (36500/tcp) + 36500/tcp: Webinterface voor Statistieken + 80/tcp: Ingebouwde Caddy Proxy HTTP Interface + 443/tcp: Ingebouwde Caddy Proxy HTTPS Interface + 443/udp: Ingebouwde Caddy Proxy HTTP/3 QUIC Interface diff --git a/cloudflared/translations/pl.yaml b/cloudflared/translations/pl.yaml index 216a8457..006348c5 100644 --- a/cloudflared/translations/pl.yaml +++ b/cloudflared/translations/pl.yaml @@ -53,4 +53,7 @@ configuration: Po ustawieniu wszystkie inne opcje zostaną zignorowane. Użyj tej opcji, jeśli skonfigurujesz tunel z Cloudflare Dashboard. network: - 36500/tcp: Metrics Web Interface (36500/tcp) + 36500/tcp: Interfejs Web Metryk + 80/tcp: Interfejs HTTP Wbudowanego Proxy Caddy + 443/tcp: Interfejs HTTPS Wbudowanego Proxy Caddy + 443/udp: Interfejs HTTP/3 QUIC Wbudowanego Proxy Caddy From cf32f7d906bc02aea96963022dac6716779d575e Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sat, 4 Oct 2025 17:30:23 -0300 Subject: [PATCH 47/55] Fix resolving Home Assistant port before it starts --- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 6c95dec8..869002c2 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -219,9 +219,11 @@ createConfig() { bashio::log.debug "Checking if SSL is used in Home Assistant..." local ha_config_file="/homeassistant/configuration.yaml" + local ha_port="8123" local ha_ssl="false" if yq . "${ha_config_file}" >/dev/null; then # https://www.home-assistant.io/integrations/http/#http-configuration-variables + ha_port=$(yq ".http.server_port // ${ha_port}" "${ha_config_file}") ha_ssl=$(yq '.http | (has("ssl_certificate") and has("ssl_key"))' "${ha_config_file}") else bashio::log.warning "No Home Assistant configuration file found, assuming no SSL" @@ -237,7 +239,7 @@ createConfig() { # Add Service for Home Assistant if 'external_hostname' is set if bashio::config.has_value 'external_hostname'; then - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_service_protocol}://homeassistant:$(bashio::core.port)\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"hostname\": \"${external_hostname}\", \"service\": \"${ha_service_protocol}://homeassistant:${ha_port}\"}]") fi # Check for configured additional hosts and add them if existing From 9208c102934a046e69c22ca84366f861061c9b0f Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sat, 4 Oct 2025 19:04:46 -0300 Subject: [PATCH 48/55] Avoid failing add-on startup if internalOnly is set without Caddy --- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 4d1f5441..10c55e7a 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -303,7 +303,8 @@ createConfig() { if bashio::var.true "${use_builtin_proxy}"; then additional_host=$(bashio::jq "${additional_host}" '.service = "https://caddy.localhost"') elif bashio::var.true "$(bashio::jq "${additional_host}" ".internalOnly")"; then - bashio::exit.nok "'additional_hosts.internalOnly' is only supported when using the built-in Caddy proxy. Please set 'use_builtin_proxy' to true or remove 'internalOnly' from the additional host configuration." + # Avoid accidental exposure of internal services when not using Caddy + continue fi # internalOnly is only for Caddy, not for Cloudflared From 9208a3775b0874a8d0be9e9406712a4bc10f9fee Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sat, 4 Oct 2025 19:50:37 -0300 Subject: [PATCH 49/55] Fix add-on not starting if use_builtin_proxy is disabled --- cloudflared/Dockerfile | 2 ++ .../etc/s6-overlay/s6-rc.d/caddy/condition_caddy.sh | 11 +++++++++++ .../rootfs/etc/s6-overlay/s6-rc.d/caddy/finish | 5 ----- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run | 6 ------ .../rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 4 ---- .../etc/s6-overlay/s6-rc.d/user/contents.d/caddy | 0 6 files changed, 13 insertions(+), 15 deletions(-) create mode 100755 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/condition_caddy.sh delete mode 100644 cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/caddy diff --git a/cloudflared/Dockerfile b/cloudflared/Dockerfile index e48c1ffd..07049f3c 100644 --- a/cloudflared/Dockerfile +++ b/cloudflared/Dockerfile @@ -2,6 +2,8 @@ FROM ghcr.io/hassio-addons/base:18.1.4 # Set S6 verbosity level ENV S6_VERBOSITY="1" +# Enable Caddy service only if enabled in config +ENV S6_STAGE2_HOOK="/etc/s6-overlay/s6-rc.d/caddy/condition_caddy.sh" # Setup base ARG BUILD_ARCH="amd64" diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/condition_caddy.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/condition_caddy.sh new file mode 100755 index 00000000..6103a621 --- /dev/null +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/condition_caddy.sh @@ -0,0 +1,11 @@ +#!/command/with-contenv bashio +# shellcheck shell=bash +# ============================================================================== +# Home Assistant Add-on: Cloudflared +# +# Decides whether to run Caddy based on the use_builtin_proxy setting or not. +# ============================================================================== + +if bashio::config.true 'use_builtin_proxy'; then + touch /etc/s6-overlay/s6-rc.d/user/contents.d/caddy +fi diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish index 659c06c8..e9424688 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish @@ -5,11 +5,6 @@ # Take down the S6 supervision tree when Caddy fails # ============================================================================== -# Avoid halting container if the built-in proxy was not enabled -if [[ ! -f /dev/shm/use_built_in_proxy ]]; then - exit 0 -fi - readonly exit_code_service="${1}" readonly exit_code_signal="${2}" exit_code_container=$(cat /run/s6-linux-init-container-results/exitcode) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run index ff81324c..1abffc37 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run @@ -1,12 +1,6 @@ #!/command/with-contenv bashio # shellcheck shell=bash -if [[ ! -f /dev/shm/use_built_in_proxy ]]; then - # Tell S6-Overlay not to restart this service - s6-svc -O . - exit 0 -fi - bashio::log.info "Starting Caddy..." exec s6-notifyoncheck -c /etc/s6-overlay/s6-rc.d/caddy/check_readiness.sh \ env XDG_DATA_HOME=/data caddy run --config /etc/caddy/Caddyfile diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 10c55e7a..f4eed8a1 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -410,7 +410,6 @@ configureCaddy() { bashio::log.trace "${FUNCNAME[0]}" if bashio::var.false "${use_builtin_proxy}"; then - bashio::log.info "Using Cloudflared without the built-in Caddy proxy" return "${__BASHIO_EXIT_OK}" fi @@ -444,9 +443,6 @@ configureCaddy() { bashio::log.info "Adding host entry for communication between Cloudflared and Caddy..." echo "127.0.0.1 caddy.localhost" | tee -a /etc/hosts - - # Signal Caddy service to run - touch /dev/shm/use_built_in_proxy } # ============================================================================== diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/caddy b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/user/contents.d/caddy deleted file mode 100644 index e69de29b..00000000 From 8088f1c1cdd8d67f4003efaf8b3db7c01f5769d6 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sat, 4 Oct 2025 19:59:36 -0300 Subject: [PATCH 50/55] Combine checkConfig with setGlobalVars and optimize additional_hosts handling --- .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 142 +++++++++--------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index f4eed8a1..07651a30 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -8,11 +8,11 @@ # ============================================================================== # ------------------------------------------------------------------------------ -# Checks if the config is valid +# Validates configuration and sets global variables used in the script # ------------------------------------------------------------------------------ -checkConfig() { +validateConfigAndSetVars() { bashio::log.trace "${FUNCNAME[0]}" - bashio::log.info "Checking add-on config..." + bashio::log.info "Validating add-on configuration..." local validHostnameRegex="^(([a-z0-9äöüß]|[a-z0-9äöüß][a-z0-9äöüß\-]*[a-z0-9äöüß])\.)*([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$" @@ -27,18 +27,38 @@ checkConfig() { bashio::exit.nok "Cannot run without tunnel_token, external_hostname, additional_hosts, catch_all_service or nginx_proxy_manager. Please set at least one of these add-on options." fi - # Check if 'external_hostname' includes a valid hostname + # Set and validate external_hostname if bashio::config.has_value 'external_hostname'; then - if ! [[ $(bashio::config 'external_hostname') =~ ${validHostnameRegex} ]]; then - bashio::exit.nok "'$(bashio::config 'external_hostname')' is not a valid hostname. Please make sure not to include the protocol (e.g. 'https://') nor the port (e.g. ':8123') and only use lowercase characters in the 'external_hostname'." + external_hostname="$(bashio::config 'external_hostname')" + if ! [[ ${external_hostname} =~ ${validHostnameRegex} ]]; then + bashio::exit.nok "'${external_hostname}' is not a valid hostname. Please make sure not to include the protocol (e.g. 'https://') nor the port (e.g. ':8123') and only use lowercase characters in the 'external_hostname'." + fi + else + external_hostname="" + fi + bashio::log.debug "external_hostname: ${external_hostname}" + + # Set and validate use_builtin_proxy + if bashio::config.true 'use_builtin_proxy'; then + use_builtin_proxy=true + # Check if 'use_builtin_proxy' is true and 'external_hostname' is empty + if bashio::var.is_empty "${external_hostname}"; then + bashio::exit.nok "'use_builtin_proxy' can only be used if 'external_hostname' is set. Please set 'external_hostname' or disable 'use_builtin_proxy'" fi + else + use_builtin_proxy=false fi + bashio::log.debug "use_builtin_proxy: ${use_builtin_proxy}" - # Check if all defined 'additional_hosts' have non-empty strings as hostname and service + # Set and validate additional_hosts if bashio::config.has_value 'additional_hosts'; then + additional_hosts=$(bashio::jq "$(bashio::addon.config)" ".additional_hosts[]") + readarray -t additional_hosts <<<"${additional_hosts}" + + local additional_host local hostname local service - for additional_host in $(bashio::jq "/data/options.json" ".additional_hosts[]"); do + for additional_host in "${additional_hosts[@]}"; do bashio::log.debug "Checking host ${additional_host}..." hostname=$(bashio::jq "${additional_host}" ".hostname") service=$(bashio::jq "${additional_host}" ".service") @@ -56,9 +76,11 @@ checkConfig() { bashio::exit.nok "'service' in 'additional_hosts' for hostname ${hostname} is empty, please enter a valid String" fi done + else + additional_hosts=() fi - # Check if 'catch_all_service' is included in config with an empty String + # Validate catch_all_service if bashio::config.exists 'catch_all_service' && bashio::config.is_empty 'catch_all_service'; then bashio::exit.nok "'catch_all_service' is defined as an empty String. Please remove 'catch_all_service' from the configuration or enter a valid String" fi @@ -68,19 +90,7 @@ checkConfig() { bashio::exit.nok "The config includes 'nginx_proxy_manager' and 'catch_all_service'. Please delete one of them since they are mutually exclusive" fi - # Check if 'use_builtin_proxy' is true and 'external_hostname' is empty - if bashio::config.true 'use_builtin_proxy' && bashio::config.is_empty 'external_hostname'; then - bashio::exit.nok "'use_builtin_proxy' can only be used if 'external_hostname' is set. Please set 'external_hostname' or disable 'use_builtin_proxy'" - fi -} - -# ------------------------------------------------------------------------------ -# Sets global variables used in the script -# ------------------------------------------------------------------------------ -setGlobalVars() { - bashio::log.trace "${FUNCNAME[0]}" - - default_config="/tmp/config.json" + # Set other global variables tunnel_uuid="" data_path="/data" @@ -109,26 +119,12 @@ setGlobalVars() { ha_url="${ha_protocol}://homeassistant:${ha_port}" bashio::log.debug "ha_url: ${ha_url}" - if bashio::config.has_value 'external_hostname'; then - external_hostname="$(bashio::config 'external_hostname')" - else - external_hostname="" - fi - bashio::log.debug "external_hostname: ${external_hostname}" - if bashio::config.has_value 'tunnel_name'; then tunnel_name="$(bashio::config 'tunnel_name')" else tunnel_name="homeassistant" fi bashio::log.debug "tunnel_name: ${tunnel_name}" - - if bashio::config.true 'use_builtin_proxy'; then - use_builtin_proxy=true - else - use_builtin_proxy=false - fi - bashio::log.debug "use_builtin_proxy: ${use_builtin_proxy}" } # ------------------------------------------------------------------------------ @@ -239,7 +235,7 @@ hasTunnel() { if [[ $tunnel_name != "$existing_tunnel_name" ]]; then bashio::log.error "Existing Cloudflare Tunnel name does not match add-on config." bashio::log.error "---------------------------------------" - bashio::log.error "Add-on Configuration tunnel name: ${tunnel_name}" + bashio::log.errorRUN "Add-on Configuration tunnel name: ${tunnel_name}" bashio::log.error "Tunnel credentials file tunnel name: ${existing_tunnel_name}" bashio::log.error "---------------------------------------" bashio::log.error "Align add-on configuration to match existing tunnel credential file" @@ -289,31 +285,30 @@ createConfig() { fi # Check for configured additional hosts and add them if existing - if bashio::config.has_value 'additional_hosts'; then - # Loop additional_hosts to create json config - while read -r additional_host; do - # Check for originRequest configuration option: disableChunkedEncoding - disableChunkedEncoding=$(bashio::jq "${additional_host}" ". | select(.disableChunkedEncoding != null) | .disableChunkedEncoding ") - if ! [[ ${disableChunkedEncoding} == "" ]]; then - additional_host=$(bashio::jq "${additional_host}" "del(.disableChunkedEncoding)") - additional_host=$(bashio::jq "${additional_host}" ".originRequest += {\"disableChunkedEncoding\": ${disableChunkedEncoding}}") - fi + local additional_host + local disableChunkedEncoding + for additional_host in "${additional_hosts[@]}"; do + # Make Cloudflared always reach the Caddy proxy if enabled + if bashio::var.true "${use_builtin_proxy}"; then + additional_host=$(bashio::jq "${additional_host}" '.service = "https://caddy.localhost"') + elif bashio::var.true "$(bashio::jq "${additional_host}" ".internalOnly")"; then + # Avoid accidental exposure of internal services when not using Caddy + continue + fi - # Make Cloudflared always reach the Caddy proxy if enabled - if bashio::var.true "${use_builtin_proxy}"; then - additional_host=$(bashio::jq "${additional_host}" '.service = "https://caddy.localhost"') - elif bashio::var.true "$(bashio::jq "${additional_host}" ".internalOnly")"; then - # Avoid accidental exposure of internal services when not using Caddy - continue - fi + # internalOnly is only relevant for Caddy, not for Cloudflared + additional_host=$(bashio::jq "${additional_host}" "del(.internalOnly)") - # internalOnly is only for Caddy, not for Cloudflared - additional_host=$(bashio::jq "${additional_host}" "del(.internalOnly)") + # Check for originRequest configuration option: disableChunkedEncoding + disableChunkedEncoding=$(bashio::jq "${additional_host}" ". | select(.disableChunkedEncoding != null) | .disableChunkedEncoding ") + if ! [[ ${disableChunkedEncoding} == "" ]]; then + additional_host=$(bashio::jq "${additional_host}" "del(.disableChunkedEncoding)") + additional_host=$(bashio::jq "${additional_host}" ".originRequest += {\"disableChunkedEncoding\": ${disableChunkedEncoding}}") + fi - # Add additional_host config to ingress config - config=$(bashio::jq "${config}" ".ingress[.ingress | length ] |= . + ${additional_host}") - done <<<"$(jq -c '.additional_hosts[]' /data/options.json)" - fi + # Add additional_host config to ingress config + config=$(bashio::jq "${config}" ".ingress[.ingress | length ] |= . + ${additional_host}") + done # Check if NGINX Proxy Manager is used to finalize configuration if bashio::config.true 'nginx_proxy_manager'; then @@ -345,6 +340,7 @@ createConfig() { fi # Write content of config variable to config file for cloudflared + local default_config="/tmp/config.json" bashio::jq "${config}" "." >"${default_config}" # Validate config using cloudflared @@ -370,13 +366,19 @@ createDNS() { fi # Check for configured additional hosts and create DNS entries for them if existing - if bashio::config.has_value 'additional_hosts'; then - for host in $(bashio::jq "/data/options.json" ".additional_hosts[].hostname"); do - bashio::log.info "Creating DNS entry ${host}..." - cloudflared --origincert="${data_path}/cert.pem" tunnel --loglevel "${CLOUDFLARED_LOG}" route dns -f "${tunnel_uuid}" "${host}" || - bashio::exit.nok "Failed to create DNS entry ${host}." - done - fi + local additional_host + local hostname + for additional_host in "${additional_hosts[@]}"; do + if bashio::var.false "${use_builtin_proxy}" && bashio::var.true "$(bashio::jq "${additional_host}" ".internalOnly")"; then + # Avoid accidental exposure of internal services when not using Caddy + continue + fi + + hostname=$(bashio::jq "${additional_host}" ".hostname") + bashio::log.info "Creating DNS entry ${hostname}..." + cloudflared --origincert="${data_path}/cert.pem" tunnel --loglevel "${CLOUDFLARED_LOG}" route dns -f "${tunnel_uuid}" "${hostname}" || + bashio::exit.nok "Failed to create DNS entry ${hostname}." + done } # ------------------------------------------------------------------------------ @@ -424,13 +426,13 @@ configureCaddy() { fi bashio::log.info "Generating Caddyfile..." - additional_hosts=$(bashio::jq "/data/options.json" ".additional_hosts") + additional_hosts_json=$(bashio::jq "$(bashio::addon.config)" ".additional_hosts") tempio_input=$( jq -n \ --argjson auto_https "${auto_https}" \ --arg ha_external_hostname "${external_hostname}" \ --arg ha_service_url "${ha_url}" \ - --argjson additional_hosts "${additional_hosts}" \ + --argjson additional_hosts "${additional_hosts_json}" \ '{auto_https: $auto_https, ha_external_hostname: $ha_external_hostname, ha_service_url: $ha_service_url, additional_hosts: $additional_hosts}' ) bashio::log.debug "Tempio input for generating Caddyfile:\n${tempio_input}" @@ -451,9 +453,7 @@ configureCaddy() { main() { bashio::log.trace "${FUNCNAME[0]}" - checkConfig - - setGlobalVars + validateConfigAndSetVars configureCaddy From 9407332f6701e4bc7700c531c7cfffeb00f0440f Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sat, 4 Oct 2025 20:12:05 -0300 Subject: [PATCH 51/55] Fix some order changes --- .../etc/s6-overlay/s6-rc.d/prepare/run.sh | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 07651a30..c3fbe802 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -27,7 +27,7 @@ validateConfigAndSetVars() { bashio::exit.nok "Cannot run without tunnel_token, external_hostname, additional_hosts, catch_all_service or nginx_proxy_manager. Please set at least one of these add-on options." fi - # Set and validate external_hostname + # Set and validate 'external_hostname' if bashio::config.has_value 'external_hostname'; then external_hostname="$(bashio::config 'external_hostname')" if ! [[ ${external_hostname} =~ ${validHostnameRegex} ]]; then @@ -38,7 +38,7 @@ validateConfigAndSetVars() { fi bashio::log.debug "external_hostname: ${external_hostname}" - # Set and validate use_builtin_proxy + # Set and validate 'use_builtin_proxy' if bashio::config.true 'use_builtin_proxy'; then use_builtin_proxy=true # Check if 'use_builtin_proxy' is true and 'external_hostname' is empty @@ -80,7 +80,7 @@ validateConfigAndSetVars() { additional_hosts=() fi - # Validate catch_all_service + # Check 'catch_all_service' if bashio::config.exists 'catch_all_service' && bashio::config.is_empty 'catch_all_service'; then bashio::exit.nok "'catch_all_service' is defined as an empty String. Please remove 'catch_all_service' from the configuration or enter a valid String" fi @@ -411,10 +411,6 @@ setCloudflaredLogLevel() { configureCaddy() { bashio::log.trace "${FUNCNAME[0]}" - if bashio::var.false "${use_builtin_proxy}"; then - return "${__BASHIO_EXIT_OK}" - fi - bashio::log.info "Configuring built-in Caddy proxy..." if [[ "$(bashio::addon.port "443/tcp")" == "443" ]]; then @@ -453,23 +449,25 @@ configureCaddy() { main() { bashio::log.trace "${FUNCNAME[0]}" - validateConfigAndSetVars - - configureCaddy - setCloudflaredLogLevel + # Run service with tunnel token without creating config + if bashio::config.has_value 'tunnel_token'; then + bashio::log.info "Using Cloudflare Remote Management Tunnel" + bashio::log.info "All add-on configuration options except tunnel_token will be ignored." + bashio::exit.ok + fi + # Run connectivity checks if debug mode activated if bashio::debug; then bashio::log.debug "Checking connectivity to Cloudflare" checkConnectivity fi - # Run service with tunnel token without creating config - if bashio::config.has_value 'tunnel_token'; then - bashio::log.info "Using Cloudflare Remote Management Tunnel" - bashio::log.info "All add-on configuration options except tunnel_token will be ignored." - bashio::exit.ok + validateConfigAndSetVars + + if bashio::var.true "${use_builtin_proxy}"; then + configureCaddy fi if ! hasCertificate; then From 697bcac27883d7c539c5eefafd5b38dbc9dc88ac Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sat, 4 Oct 2025 20:13:20 -0300 Subject: [PATCH 52/55] Oops --- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index c3fbe802..eaed03a2 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -235,7 +235,7 @@ hasTunnel() { if [[ $tunnel_name != "$existing_tunnel_name" ]]; then bashio::log.error "Existing Cloudflare Tunnel name does not match add-on config." bashio::log.error "---------------------------------------" - bashio::log.errorRUN "Add-on Configuration tunnel name: ${tunnel_name}" + bashio::log.error "Add-on Configuration tunnel name: ${tunnel_name}" bashio::log.error "Tunnel credentials file tunnel name: ${existing_tunnel_name}" bashio::log.error "---------------------------------------" bashio::log.error "Align add-on configuration to match existing tunnel credential file" From ca378482b85bc6a0538602d755845f0c631b849f Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 6 Oct 2025 18:30:54 -0300 Subject: [PATCH 53/55] Remove useless code --- cloudflared/DOCS.md | 10 ---------- .../rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 13 +++++++++---- cloudflared/rootfs/run.sh | 16 ---------------- 3 files changed, 9 insertions(+), 30 deletions(-) diff --git a/cloudflared/DOCS.md b/cloudflared/DOCS.md index 755c2585..078ac5f1 100644 --- a/cloudflared/DOCS.md +++ b/cloudflared/DOCS.md @@ -69,14 +69,6 @@ Trust Dashboard and provide the token to the add-on. Your tunnel should now be associated with the Cloudflared add-on. Any configuration changes should be made in the Cloudflare Teams dashboard. -If you would like to use the add-on built-in proxy, you should still set the -`external_hostname` option and optionally the `additional_hosts` option because -the built-in proxy needs to know the domain names to serve. - -In your remotely managed tunnel, you can then set the service URL to -`https://caddy.localhost` if you wish to forward requests to the built-in -proxy. - ## Configuration **These configuration options only apply to the local tunnel setup**. More @@ -116,8 +108,6 @@ to use to access Home Assistant on. This is optional, `additional_hosts` can be used instead to only expose other services. -**Note**: _The tunnel name needs to be unique in your Cloudflare account._ - ```yaml external_hostname: ha.example.com ``` diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index cf4451c3..d124aba1 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -18,8 +18,7 @@ validateConfigAndSetVars() { # Check for minimum configuration options if - bashio::config.is_empty 'tunnel_token' && - bashio::config.is_empty 'external_hostname' && + bashio::config.is_empty 'external_hostname' && bashio::config.is_empty 'additional_hosts' && bashio::config.is_empty 'catch_all_service' && bashio::config.is_empty 'nginx_proxy_manager' @@ -80,7 +79,7 @@ validateConfigAndSetVars() { additional_hosts=() fi - # Check 'catch_all_service' + # Check if 'catch_all_service' is included in config with an empty String if bashio::config.exists 'catch_all_service' && bashio::config.is_empty 'catch_all_service'; then bashio::exit.nok "'catch_all_service' is defined as an empty String. Please remove 'catch_all_service' from the configuration or enter a valid String" fi @@ -314,7 +313,7 @@ createConfig() { if bashio::config.true 'nginx_proxy_manager'; then bashio::log.warning "Runing with Nginxproxymanager support, make sure the add-on is installed and running." - config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://a0d7b954-nginxproxymanager\"}]") + config=$(bashio::jq "${config}" ".\"ingress\" += [{\"service\": \"http://a0d7b954-nginxproxymanager:80\"}]") else # Check if catch all service is defined @@ -451,6 +450,12 @@ main() { setCloudflaredLogLevel + # Run connectivity checks if debug mode activated + if bashio::debug; then + bashio::log.debug "Checking connectivity to Cloudflare" + checkConnectivity + fi + # Run service with tunnel token without creating config if bashio::config.has_value 'tunnel_token'; then bashio::log.info "Using Cloudflare Remote Management Tunnel" diff --git a/cloudflared/rootfs/run.sh b/cloudflared/rootfs/run.sh index ab11666a..5aada2eb 100755 --- a/cloudflared/rootfs/run.sh +++ b/cloudflared/rootfs/run.sh @@ -38,22 +38,6 @@ else options+=(run "$(bashio::config 'tunnel_name')") fi -function wait_for_file() { - local file="$1" - local timeout="$2" - local interval=1 - local elapsed=0 - - while [[ ! -f "${file}" && ${elapsed} -lt ${timeout} ]]; do - sleep "${interval}" - elapsed=$((elapsed + interval)) - done - - if [[ ! -f "${file}" ]]; then - bashio::exit.nok "Timed out waiting for ${file} to be created." - fi -} - bashio::log.info "Connecting Cloudflare Tunnel..." bashio::log.debug "cloudflared tunnel ${options[*]}" exec cloudflared tunnel "${options[@]}" From 8c4c3c310d53053189d1179b7de5cc27621fb19a Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 6 Oct 2025 18:35:07 -0300 Subject: [PATCH 54/55] Allow running Caddy with additional_hosts only --- cloudflared/rootfs/etc/caddy/Caddyfile.gtpl | 4 +++- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl index 549ba5c2..6d9fc6a8 100644 --- a/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl +++ b/cloudflared/rootfs/etc/caddy/Caddyfile.gtpl @@ -17,7 +17,7 @@ # Used for communication between Cloudflared and Caddy https://caddy.localhost { - tls internal + tls internal # Used to ensure Caddy is ready before starting Cloudflared respond /healthz 200 @@ -25,6 +25,7 @@ https://caddy.localhost { respond 403 } +{{ if .ha_external_hostname }} {{ .ha_external_hostname }} { @cloudflared remote_ip 127.0.0.1 @@ -44,6 +45,7 @@ https://caddy.localhost { } }{{ end }} } +{{ end }} {{ range $i, $e := .additional_hosts }} {{ $e.hostname }} { diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index d124aba1..030650a5 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -40,10 +40,6 @@ validateConfigAndSetVars() { # Set and validate 'use_builtin_proxy' if bashio::config.true 'use_builtin_proxy'; then use_builtin_proxy=true - # Check if 'use_builtin_proxy' is true and 'external_hostname' is empty - if bashio::var.is_empty "${external_hostname}"; then - bashio::exit.nok "'use_builtin_proxy' can only be used if 'external_hostname' is set. Please set 'external_hostname' or disable 'use_builtin_proxy'" - fi else use_builtin_proxy=false fi From 71dcbb37159354bbb9764d1b20e6cec62f0b2b3c Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 6 Oct 2025 18:41:01 -0300 Subject: [PATCH 55/55] Avoid parsing HA config if not needed (external_hostname unset) --- cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh index 030650a5..a20cbba9 100755 --- a/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh +++ b/cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh @@ -93,7 +93,9 @@ validateConfigAndSetVars() { local ha_config_file="/homeassistant/configuration.yaml" local ha_port="8123" local ha_ssl="false" - if yq . "${ha_config_file}" >/dev/null; then + if bashio::var.is_empty "${external_hostname}"; then + bashio::log.debug "No external_hostname configured, skipping check of Home Assistant port and SSL" + elif yq . "${ha_config_file}" >/dev/null; then # https://www.home-assistant.io/integrations/http/#http-configuration-variables ha_port=$(yq ".http.server_port // ${ha_port}" "${ha_config_file}") ha_ssl=$(yq '.http | (has("ssl_certificate") and has("ssl_key"))' "${ha_config_file}") @@ -354,7 +356,7 @@ createDNS() { bashio::log.trace "${FUNCNAME[0]}" # Create DNS entry for external hostname of Home Assistant if 'external_hostname' is set - if bashio::config.has_value 'external_hostname'; then + if bashio::var.has_value "${external_hostname}"; then bashio::log.info "Creating DNS entry ${external_hostname}..." cloudflared --origincert="${data_path}/cert.pem" tunnel --loglevel "${CLOUDFLARED_LOG}" route dns -f "${tunnel_uuid}" "${external_hostname}" || bashio::exit.nok "Failed to create DNS entry ${external_hostname}."