added cloudflare-tunnel
This commit is contained in:
@@ -36,6 +36,7 @@ handled separately — see [Exposing services](#exposing-services).
|
|||||||
|
|
||||||
| Service | Port | Notes |
|
| Service | Port | Notes |
|
||||||
|---------|------|-------|
|
|---------|------|-------|
|
||||||
|
| [cloudflare-tunnel](cloudflare-tunnel/) | — | Outbound connector. Exposes other services without opening a port |
|
||||||
| [jellyfin](jellyfin/) | 8096 | Media streaming. Also 7359/udp for auto-discovery |
|
| [jellyfin](jellyfin/) | 8096 | Media streaming. Also 7359/udp for auto-discovery |
|
||||||
| [openwebui](openwebui/) | 3033 | LLM chat UI, talks to an external model backend |
|
| [openwebui](openwebui/) | 3033 | LLM chat UI, talks to an external model backend |
|
||||||
| [owui-ollama](owui-ollama/) | 3034 | Open WebUI bundled with Ollama |
|
| [owui-ollama](owui-ollama/) | 3034 | Open WebUI bundled with Ollama |
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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>
|
||||||
@@ -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
|
||||||
@@ -33,15 +33,19 @@ TODO: your preferred flow — dashboard-created tunnel vs. `cloudflared tunnel
|
|||||||
create`. The dashboard route is easier to show on video; the CLI route is
|
create`. The dashboard route is easier to show on video; the CLI route is
|
||||||
easier to keep in version control.
|
easier to keep in version control.
|
||||||
|
|
||||||
|
The connector itself is a service in this repo — see
|
||||||
|
[`cloudflare-tunnel/`](../cloudflare-tunnel/) for the compose file, the token
|
||||||
|
setup and the gotchas. In short:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
cloudflared:
|
cloudflaretunnel:
|
||||||
image: cloudflare/cloudflared:latest
|
image: cloudflare/cloudflared:latest
|
||||||
container_name: cloudflared
|
container_name: cloudflare-tunnel
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: tunnel --no-autoupdate run
|
command: tunnel --no-autoupdate run
|
||||||
environment:
|
environment:
|
||||||
- TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
|
- TUNNEL_TOKEN=${TUNNEL_TOKEN:?}
|
||||||
```
|
```
|
||||||
|
|
||||||
The tunnel token is a **real secret** — it grants the ability to route
|
The tunnel token is a **real secret** — it grants the ability to route
|
||||||
|
|||||||
Reference in New Issue
Block a user