Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
4b86dff
Add caddy as internal proxy
felipecrs May 21, 2025
c1f43e0
Refactor some stuff
felipecrs May 23, 2025
7b2a15c
Handle auto https
felipecrs May 23, 2025
f84bbcb
Clean some things up
felipecrs May 23, 2025
f642b84
More cleanup
felipecrs May 23, 2025
77da04c
Fix initial certificate generation again
felipecrs May 23, 2025
95b5f53
More cleanup
felipecrs May 24, 2025
e3d3202
Handle SSL in service and HA
felipecrs May 24, 2025
529a625
Update docs and avoid starting caddy when built-in proxy is disabled
felipecrs May 26, 2025
5f6abbb
Prettified Code!
felipecrs May 26, 2025
539b3e2
Setup catch all service
felipecrs May 27, 2025
01f3a39
Restore addon version
felipecrs May 27, 2025
681e655
Fix some markdown lint
felipecrs May 27, 2025
51150d6
Fix another one
felipecrs May 27, 2025
11c6521
Add bullet point for internalOnly
felipecrs May 27, 2025
c48b07a
Fix some @coderabiitai comments
felipecrs May 27, 2025
f5a9965
Address some comments
felipecrs Jun 11, 2025
53f0e16
Merge branch 'main' into caddy-internal-proxy
felipecrs Jun 11, 2025
2990d75
Refactor Caddyfile
felipecrs Jun 11, 2025
8ce1028
Improve condition name
felipecrs Jun 11, 2025
fb43445
Handle catch all service with https
felipecrs Jun 11, 2025
91f7d00
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Jun 11, 2025
159cb8e
Fix 127.0.0.1 login notifications with Caddy
felipecrs Jun 12, 2025
97ea8a6
Wait for Caddy to be ready before starting Cloudflared
felipecrs Jun 12, 2025
8b95267
Enable HTTP/2 between Cloudflared and Caddy
felipecrs Jun 12, 2025
8a32111
Avoid using noTLSVerify for communication between Cloudflared and Caddy
felipecrs Jun 12, 2025
c265f15
Avoid unnecessary attempt to install root CA
felipecrs Jun 12, 2025
dbb2c8b
Disable persisting the generated json config
felipecrs Jun 12, 2025
c99fe1a
Disable unused admin API
felipecrs Jun 12, 2025
966ebf7
Improve log format, including colors
felipecrs Jun 12, 2025
2db2e97
Use HTTPS for catchall
felipecrs Jun 12, 2025
df9734f
Update cloudflared/rootfs/etc/s6-overlay/s6-rc.d/prepare/run.sh
felipecrs Jun 12, 2025
d91e8fb
Refactor tls on_demand for wildcard cert
felipecrs Jun 14, 2025
107b530
Simplify caddy healthcheck
felipecrs Jun 15, 2025
c718e11
Stop using Caddy for catch-all
felipecrs Jun 15, 2025
9bd4ca0
Cleanup some code
felipecrs Jun 15, 2025
780ad44
Merge branch 'main' into caddy-internal-proxy
elcajon Jun 17, 2025
35f9635
Merge branch 'main' into caddy-internal-proxy
felipecrs Jun 22, 2025
d51978f
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Jul 4, 2025
611bd1c
Prettified Code!
felipecrs Jul 4, 2025
e3a9ad0
Prepare for remotely managed tunnels
felipecrs Jul 6, 2025
c653629
Use bashio to get forwarded addon port 443
felipecrs Jul 6, 2025
f1e854f
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Jul 11, 2025
38d0344
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Aug 8, 2025
ff62946
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Aug 8, 2025
81962c4
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Aug 8, 2025
58980fd
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Aug 8, 2025
90a217f
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Aug 10, 2025
17dc293
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Aug 12, 2025
857425f
Merge branch 'main' into caddy-internal-proxy
elcajon Aug 21, 2025
c0a721c
Update Caddy to 2.10.1
felipecrs Aug 22, 2025
22804ec
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Aug 23, 2025
f0a9d60
Implement s6-overlay native readiness check for caddy service
felipecrs Aug 26, 2025
e5e40d7
Update Caddy to 2.10.2
felipecrs Aug 26, 2025
bdc0cd2
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Sep 19, 2025
a2098f4
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Sep 24, 2025
46c3f37
Translations: replace Nginx with Caddy
elcajon Sep 24, 2025
121a222
Merge branch 'remove-nginx' of https://github.com/brenner-tobias/addo…
felipecrs Sep 29, 2025
114cf56
Add checks to prevent startup with invalid use_builtin_proxy settings
felipecrs Sep 29, 2025
30326eb
Update use_builtin_proxy docs and disable it by default
felipecrs Sep 29, 2025
fdf185c
Remove unnecessary check and fix tunnel_token check
felipecrs Sep 29, 2025
fc94a2f
Fix S6 starting Caddy if tunnel_token is set
felipecrs Sep 29, 2025
a0522f3
Add translations for new network ports
felipecrs Sep 29, 2025
1df0fc3
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Sep 30, 2025
cf32f7d
Fix resolving Home Assistant port before it starts
felipecrs Oct 4, 2025
6ce229b
Merge branch 'fix-ha-port' of https://github.com/brenner-tobias/addon…
felipecrs Oct 4, 2025
4a20230
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Oct 4, 2025
9208c10
Avoid failing add-on startup if internalOnly is set without Caddy
felipecrs Oct 4, 2025
9208a37
Fix add-on not starting if use_builtin_proxy is disabled
felipecrs Oct 4, 2025
8088f1c
Combine checkConfig with setGlobalVars and optimize additional_hosts …
felipecrs Oct 4, 2025
9407332
Fix some order changes
felipecrs Oct 4, 2025
697bcac
Oops
felipecrs Oct 4, 2025
f32d720
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Oct 6, 2025
ca37848
Remove useless code
felipecrs Oct 6, 2025
8c4c3c3
Allow running Caddy with additional_hosts only
felipecrs Oct 6, 2025
71dcbb3
Avoid parsing HA config if not needed (external_hostname unset)
felipecrs Oct 6, 2025
882a593
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Oct 7, 2025
d10b0e4
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Oct 22, 2025
49faad1
Merge branch 'main' of https://github.com/brenner-tobias/addon-cloudf…
felipecrs Nov 19, 2025
b47d2d3
Merge branch 'main' into caddy-internal-proxy
felipecrs Nov 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions cloudflared/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,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
Expand Down Expand Up @@ -215,6 +219,69 @@ in Cloudflare by adding a CNAME record with `*` as name.
Finally, you have to set-up your proxy hosts in Nginx Proxy Manager and forward
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 allows a unified access to Home
Assistant and additional hosts even within your local network.

**Note**: _This option is disabled by default._

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_:
- `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

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`.

If you are using OpenWRT, you can do it from _Network_ > _DHCP and DNS_ >
_DNS Records_ > _Hostnames_.

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` 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 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/`.

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 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.

### Option: `post_quantum`

If you want Cloudflared to use post-quantum cryptography for the tunnel,
Expand Down
4 changes: 4 additions & 0 deletions cloudflared/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ FROM ghcr.io/hassio-addons/base:19.0.0

# 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"

# renovate: datasource=repology depName=yq packageName=alpine_3_22/yq-go versioning=loose
ARG YQ_VERSION="4.47.2-r1"
# renovate: datasource=github-releases depName=caddy packageName=caddyserver/caddy
ARG CADDY_VERSION="2.10.2"
# renovate: datasource=github-releases depName=cloudflared packageName=cloudflare/cloudflared versioning=loose
ARG CLOUDFLARED_VERSION="2025.11.1"

Expand Down
8 changes: 8 additions & 0 deletions cloudflared/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,23 @@ options:
additional_hosts: []
ports:
36500/tcp: null
80/tcp: null
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?
additional_hosts:
- hostname: str
service: str
disableChunkedEncoding: bool?
internalOnly: bool?
tunnel_name: str?
catch_all_service: str?
nginx_proxy_manager: bool?
use_builtin_proxy: bool?
tunnel_token: str?
post_quantum: bool?
run_parameters:
Expand Down
16 changes: 16 additions & 0 deletions cloudflared/rootfs/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ set -eux
# yq is to avoid depending on Home Assistant API on startup
apk add --no-cache yq-go="${YQ_VERSION}"

# 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

# 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
Expand Down
74 changes: 74 additions & 0 deletions cloudflared/rootfs/etc/caddy/Caddyfile.gtpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
# 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
skip_install_trust
{{ if not .auto_https }}
# Disable automatic generation of Let's Encrypt certificates
local_certs
{{ end }}
log {
# More friendly logging format than the default json
format console
}
}

# Used for communication between Cloudflared and Caddy
https://caddy.localhost {
tls internal

# Used to ensure Caddy is ready before starting Cloudflared
respond /healthz 200

respond 403
}

{{ if .ha_external_hostname }}
{{ .ha_external_hostname }} {
@cloudflared remote_ip 127.0.0.1

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 {
tls_insecure_skip_verify
}
{{ end }}
}

reverse_proxy {{ .ha_service_url }} {{ if hasPrefix "https://" .ha_service_url }}{
transport http {
tls_insecure_skip_verify
}
}{{ end }}
}
{{ end }}

{{ 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
handle @cloudflared {
respond 403
}
{{ else }}
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 }}
reverse_proxy {{ $e.service }} {{ if hasPrefix "https://" $e.service }}{
transport http {
tls_insecure_skip_verify
}
}{{ end }}
}
{{ end }}
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/condition_caddy.sh
Original file line number Diff line number Diff line change
@@ -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
Empty file.
30 changes: 30 additions & 0 deletions cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/finish
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/command/with-contenv bashio
# shellcheck shell=bash
# ==============================================================================
# Home Assistant Add-on: Cloudflared
# Take down the S6 supervision tree when Caddy 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="caddy"

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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3
6 changes: 6 additions & 0 deletions cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/command/with-contenv bashio
# shellcheck shell=bash

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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
15000
1 change: 1 addition & 0 deletions cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/timeout-up
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
15000
1 change: 1 addition & 0 deletions cloudflared/rootfs/etc/s6-overlay/s6-rc.d/caddy/type
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
longrun
Loading
Loading