added cloudflare-tunnel

This commit is contained in:
Goyban
2026-08-19 15:54:37 +02:00
parent 369bf69abf
commit e5a1395c12
5 changed files with 131 additions and 3 deletions
+20
View File
@@ -0,0 +1,20 @@
# Copy to .env and adjust. .env is git-ignored; this file is not.
# NEVER put the real token in this file.
# ─── Required ───────────────────────────────────────────────────────
# Cloudflare Zero Trust tunnel token.
#
# Dashboard -> Zero Trust -> Networks -> Tunnels -> (your tunnel) -> Configure
# https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/
#
# The dashboard shows a pre-filled `docker run ... --token <TOKEN>` command.
# Copy only the token itself, not the whole command.
#
# Treat it like a password: anyone holding it can route traffic into your
# network. If it leaks, delete the tunnel in the dashboard and make a new one
# — the token cannot be rotated on its own.
TUNNEL_TOKEN=
# ─── Shared ─────────────────────────────────────────────────────────
# Defaulted to Etc/UTC in compose.yaml. Only affects log timestamps here.
#TZ=Europe/Paris
+82
View File
@@ -0,0 +1,82 @@
# Cloudflare Tunnel
The `cloudflared` connector. It dials **out** to Cloudflare and Cloudflare
routes public traffic back down that connection — so a service reaches the
internet with no port forwarded, no static IP and no VPS.
One tunnel serves every service; you don't need a copy of this per app.
## Quick start
```bash
cp .env.example .env
$EDITOR .env # paste TUNNEL_TOKEN
docker compose up -d
```
Get the token at **Dashboard → Zero Trust → Networks → Tunnels →** *(your
tunnel)* **→ Configure**. The page shows a pre-filled `docker run … --token
<TOKEN>` command — copy only the token part.
Docs: <https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/>
Then add routes in the same dashboard: **Public Hostname → Service**, e.g.
`gitea.example.com → http://host.docker.internal:3000`.
## Ports
**None.** Nothing listens on the host — that's the entire point. If you find
yourself adding a `ports:` block here, something has been misunderstood.
## Why it looks like this
**The token lives in `.env`, and compose refuses to start without it.** It's
written `${TUNNEL_TOKEN:?…}` rather than with a default, because a
blank token gives you a container that starts, retries, and quietly routes
nothing. The token is a genuine credential — it authorises routing traffic
into your network — so it never belongs in a committed file.
**No `PUID`/`PGID`.** Unlike most services here, this isn't a LinuxServer
image and doesn't understand those variables. It writes nothing to disk and
needs no volumes, so there's no ownership to get right. `TZ` is kept only
because it affects log timestamps.
**`extra_hosts: host.docker.internal:host-gateway`.** Routes are configured in
the dashboard, and the connector has to resolve whatever hostname you put
there. This line lets you point at services published on the Docker host
without hardcoding the LAN IP — which would otherwise break the day your
router hands out a different lease.
**`--no-autoupdate`.** The binary can update itself in place, which means the
thing routing your traffic changes without you doing anything. Pinning that
off makes updates a deliberate `docker compose pull`.
**No config file, no volume.** This is the remotely-managed style of tunnel:
routing lives in the Cloudflare dashboard, not on disk. The trade is that your
routing config isn't in this repo — the alternative (`cloudflared tunnel
create` plus a mounted `config.yml`) is version-controllable but more setup.
## Gotchas
- **Don't put video through it.** Cloudflare's terms restrict serving large
non-HTML content, and streaming a media library is the classic way to get an
account flagged. Jellyfin belongs behind your own reverse proxy.
- **~100 MB upload cap** on the free plan. Photo backup and file sync break on
this, sometimes with nothing clearer than a `413`.
- **The token can't be rotated.** If it leaks, delete the tunnel and create a
new one.
- **A dead tunnel looks like a DNS problem.** If a hostname stops resolving,
check `docker compose logs cloudflared` before suspecting Cloudflare.
## Related
- [When to use a tunnel, and when not to](../docs/cloudflare-tunnel.md) — the
longer write-up, including the comparison against a VPS reverse proxy.
- [Reverse proxy with Caddy](../docs/reverse-proxy.md)
- [Single sign-on with Authentik](../docs/authentik-sso.md) — note Cloudflare
Access can also sit in front of a tunnel; running both is usually redundant.
## Links
- Connector docs: <https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/>
- Image: <https://hub.docker.com/r/cloudflare/cloudflared>
+21
View File
@@ -0,0 +1,21 @@
services:
cloudflaretunnel:
image: cloudflare/cloudflared:latest
container_name: cloudflare-tunnel
restart: unless-stopped
command: tunnel --no-autoupdate run
environment:
# Only affects log timestamps here — nothing is written to disk.
- TZ=${TZ:-Etc/UTC}
# A real secret: it grants the ability to route traffic into your network.
# Dashboard -> Zero Trust -> Networks -> Tunnels -> (tunnel) -> Configure
- TUNNEL_TOKEN=${TUNNEL_TOKEN:?get it from Cloudflare Zero Trust > Networks > Tunnels > Configure}
# No `ports:` and no PUID/PGID on purpose — see the README.
# Lets dashboard routes reach services published on the Docker host, e.g.
# gitea.example.com -> http://host.docker.internal:3000
# Drop this if you route to containers by name on a shared network.
extra_hosts:
- host.docker.internal:host-gateway