diff --git a/CLAUDE.md b/CLAUDE.md index fb3eeef..d1eb497 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,14 +27,14 @@ exactly. ## Architecture -**Network model:** A single Cloudflare Tunnel -(`cloudflared/`) creates and owns the `cloudflare-exposed` -external bridge network. Services that need internet -exposure declare and connect to this network. Services -that don't need Cloudflare exposure should **not** declare -any network in their compose file — Dokploy attaches its -own `dokploy-network` automatically on deploy (e.g. `n8n`, -`plex`, `traccar`, `watchtower`). +**Network model:** Services don't declare networks for +exposure. Dokploy attaches its own `dokploy-network` on +deploy to every service that has a domain, and Traefik routes +from there. The +Cloudflare Tunnel (`cloudflared/`) sends every public +hostname to `http://dokploy-traefik`. What is exposed is +decided by the tunnel's hostnames, the Dokploy domains and +Cloudflare Access, not by Docker networks. **Container management:** Watchtower handles automatic image updates using label-based opt-in diff --git a/README.md b/README.md index 399043a..caf1654 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,7 @@ this repository. 4. Run `docker compose up -d`. > Each service is self-contained. You can deploy them independently -> in any order, except that **cloudflared** should be running first -> if the service connects to the `cloudflare-exposed` network. +> in any order. ## Deployment via Dokploy diff --git a/archisteamfarm/README.md b/archisteamfarm/README.md index 096127f..9c214d6 100644 --- a/archisteamfarm/README.md +++ b/archisteamfarm/README.md @@ -36,8 +36,8 @@ With Docker Compose the real names are prefixed with the project name ## Networks -Connects to `cloudflare-exposed` -(must be created by the `cloudflared` service first). +Declares no networks. Dokploy attaches `dokploy-network` on deploy +because the service has a domain; Traefik reaches it there. ## Updates diff --git a/archisteamfarm/docker-compose.yml b/archisteamfarm/docker-compose.yml index 919bbbf..d60fc76 100644 --- a/archisteamfarm/docker-compose.yml +++ b/archisteamfarm/docker-compose.yml @@ -5,8 +5,6 @@ services: restart: unless-stopped security_opt: - no-new-privileges:true - networks: - - cloudflare-exposed volumes: - /etc/localtime:/etc/localtime:ro - archisteamfarm-config:/app/config @@ -31,7 +29,3 @@ volumes: archisteamfarm-config: archisteamfarm-plugins: archisteamfarm-logs: - -networks: - cloudflare-exposed: - external: true diff --git a/cloudflared/README.md b/cloudflared/README.md index 2c1a64b..723014a 100644 --- a/cloudflared/README.md +++ b/cloudflared/README.md @@ -4,25 +4,22 @@ Runs a [Cloudflare Tunnel][tunnel-docs] to securely expose internal Docker services to the internet without opening ports on the host. -This service creates the shared `cloudflare-exposed` bridge -network. Any service that needs external access must join -this network. - -The tunnel also attaches to the `dokploy-network` so it can -reach services that are only published on that network -(those that don't declare `cloudflare-exposed`). Dokploy -provides `dokploy-network` automatically on deploy. +The tunnel joins `dokploy-network`, which Dokploy provides +automatically on deploy, and sends every public hostname to +Traefik (`http://dokploy-traefik`). Traefik then routes the +request using the domain configured in Dokploy. ## How It Works 1. The `cloudflared` container establishes a tunnel using your Cloudflare token. -2. The `cloudflare-exposed` Docker network is created - and shared across services. -3. Services attached to this network become reachable - through Cloudflare. -4. Routes and access policies are managed in the - [Cloudflare Zero Trust dashboard][zero-trust]. +2. Each public hostname is added to the tunnel in the + [Cloudflare Zero Trust dashboard][zero-trust], pointing + to `http://dokploy-traefik`. +3. Traefik forwards the request to the service that has + that domain in Dokploy (HTTPS off, certificate None: + Cloudflare terminates TLS). +4. Access policies are managed in Cloudflare Zero Trust. ## Environment Variables @@ -30,22 +27,26 @@ provides `dokploy-network` automatically on deploy. |--------------------------|----------------------------------------| | `CLOUDFLARE_TUNNEL_TOKEN`| Tunnel token from Cloudflare Zero Trust| -## Connecting a Service - -Add the `cloudflare-exposed` network to any service -you want to expose: - -```yaml -services: - my-service: - image: example/my-service:latest - networks: - - cloudflare-exposed +## Exposing a Service +A service is exposed by configuration, not by Docker networks: - cloudflare-exposed: - external: true -``` + +1. Add the domain to the service in Dokploy. +2. Unless it must be public, create its Cloudflare Access + application first, so the hostname is never reachable + without it. +3. Add the hostname to the tunnel, pointing to + `http://dokploy-traefik`. + +No network needs to be declared in the service's compose +file. + +Traefik's ports 80 and 443 must not be reachable from the +internet. Otherwise a client could send a protected hostname +straight to Traefik and skip Cloudflare Access. On +tuckfow-cloud-01 the Hetzner firewall blocks them. At home +the router forwards no ports to the server. ## Useful Resources diff --git a/cloudflared/docker-compose.yml b/cloudflared/docker-compose.yml index b38b747..72a9312 100644 --- a/cloudflared/docker-compose.yml +++ b/cloudflared/docker-compose.yml @@ -11,7 +11,6 @@ services: - 1.0.0.1 dns_search: . networks: - - cloudflare-exposed - dokploy-network environment: - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN} @@ -22,8 +21,3 @@ services: max-file: "3" labels: - com.centurylinklabs.watchtower.enable=true - -networks: - cloudflare-exposed: - driver: bridge - name: cloudflare-exposed diff --git a/homepage/README.md b/homepage/README.md index 4899d8e..a3d50fc 100644 --- a/homepage/README.md +++ b/homepage/README.md @@ -62,8 +62,10 @@ with the named volume: ## Networks -Connects to `cloudflare-exposed` -(must be created by the `cloudflared` service first). +Declares no networks. Dokploy attaches `dokploy-network` on deploy +because the service has a domain; Traefik reaches it there. +Homepage reaches the Pi-hole and Speedtest widgets by container name +(`http://pihole`, `http://speedtest`) over that network. ## Updates diff --git a/homepage/docker-compose.yml b/homepage/docker-compose.yml index 1e29739..afbec7c 100644 --- a/homepage/docker-compose.yml +++ b/homepage/docker-compose.yml @@ -11,8 +11,6 @@ services: start_period: 30s security_opt: - no-new-privileges:true - networks: - - cloudflare-exposed volumes: - /etc/localtime:/etc/localtime:ro - homepage-config:/app/config @@ -37,7 +35,3 @@ services: volumes: homepage-config: - -networks: - cloudflare-exposed: - external: true diff --git a/pihole/README.md b/pihole/README.md index 9a13811..da32409 100644 --- a/pihole/README.md +++ b/pihole/README.md @@ -29,8 +29,11 @@ nebula-sync). ## Networks -Connects to `cloudflare-exposed` -(must be created by the `cloudflared` service first). +Declares no networks. Dokploy attaches `dokploy-network` on deploy +because the service has a domain; Traefik reaches it there. +Keep a Dokploy domain on this service: without one, Dokploy does not +attach `dokploy-network` and the Homepage widget (`http://pihole`) +can no longer reach it. ## Updates diff --git a/pihole/docker-compose.yml b/pihole/docker-compose.yml index ef6d9d3..5408856 100644 --- a/pihole/docker-compose.yml +++ b/pihole/docker-compose.yml @@ -19,8 +19,6 @@ services: timeout: 10s retries: 3 start_period: 30s - networks: - - cloudflare-exposed ports: - "53:53/tcp" - "53:53/udp" @@ -47,7 +45,3 @@ services: volumes: pihole-etc: pihole-dnsmasq: - -networks: - cloudflare-exposed: - external: true diff --git a/speedtest/README.md b/speedtest/README.md index 160e0bf..edbddf1 100644 --- a/speedtest/README.md +++ b/speedtest/README.md @@ -24,12 +24,15 @@ Named Docker volume, so it can be backed up with Dokploy volume backups. With Docker Compose the real name is prefixed with the project name (for example `_speedtest-config`). -## Networks +[speedtest-tracker]: https://github.com/alexjustesen/speedtest-tracker -Connects to `cloudflare-exposed` -(must be created by the `cloudflared` service first). +## Networks -[speedtest-tracker]: https://github.com/alexjustesen/speedtest-tracker +Declares no networks. Dokploy attaches `dokploy-network` on deploy +because the service has a domain; Traefik reaches it there. +Keep a Dokploy domain on this service: without one, Dokploy does not +attach `dokploy-network` and the Homepage widget (`http://speedtest`) +can no longer reach it. ## Updates diff --git a/speedtest/docker-compose.yml b/speedtest/docker-compose.yml index 675ecf4..d90ca28 100644 --- a/speedtest/docker-compose.yml +++ b/speedtest/docker-compose.yml @@ -12,8 +12,6 @@ services: timeout: 10s retries: 3 start_period: 30s - networks: - - cloudflare-exposed volumes: - speedtest-config:/config environment: @@ -46,7 +44,3 @@ services: volumes: speedtest-config: - -networks: - cloudflare-exposed: - external: true