From 1c7e280855bedfa4ff214033f98d0353bcfb61d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Mon, 7 Sep 2026 23:26:08 +0200 Subject: [PATCH] docs: document warden share and the Cloudflare Tunnel provider Add configuration/share.md covering the share command, the traffic path through Traefik, per-developer and per-project configuration, Cloudflare Tunnel setup including the DNS record, configuration regeneration and troubleshooting. List the share agent under global services, add a feature bullet, and document .env.local overrides in customizing.md. --- configuration/share.md | 117 ++++++++++++++++++++++++++++++++++++ environments/customizing.md | 4 ++ index.md | 1 + services.md | 1 + 4 files changed, 123 insertions(+) create mode 100644 configuration/share.md diff --git a/configuration/share.md b/configuration/share.md new file mode 100644 index 0000000..59b1997 --- /dev/null +++ b/configuration/share.md @@ -0,0 +1,117 @@ +# Sharing A Project Publicly + +`warden share` exposes a running project to the public internet through a share provider, without deploying anywhere. This is useful for: + +- Receiving webhooks or payment provider callbacks that need a publicly reachable URL +- Showing work in progress to a client or teammate +- Testing on a real mobile device over a real domain instead of `.test` + +## How It Fits Warden's Architecture + +A share provider runs as a global service, started with `warden svc up` alongside Traefik and the other {doc}`global services <../services>`. The provider's container joins the `warden` network and forwards incoming public traffic to Traefik, which then routes it exactly the way it routes local `.test` traffic: by matching the `Host` header to the project's Nginx or Varnish container. + +``` +Internet -> provider edge -> share agent (warden network) -> Traefik -> Nginx/Varnish +``` + +Because routing happens at the Traefik layer, sharing a project does not change how the project itself is configured. The same container serves both `myproject.test` and the public hostname. + +## User Configuration + +### Global, Per-Developer (`~/.warden/.env`) + +* `WARDEN_SHARE_PROVIDER` selects the share provider, for example `cloudflared`. + +This setting belongs in `~/.warden/.env`, not in any project's `.env`. `~/.warden/.env` lives outside every project repository, so the tunnel credentials and tunnel identity it references stay tied to the developer's own account rather than being shared or committed to a project. + +### Per Project (`.env`) + +* `TRAEFIK_PUBLIC_DOMAIN` is the public hostname for the project, for example `myproject.example.com`. + +The value must be a plain hostname: letters, digits and hyphens, with at least one dot. `warden env up` rejects anything else, since the value is used verbatim in a Traefik router rule and in the provider's ingress configuration. + +If a developer wants to use a personal hostname without committing it to the project, `TRAEFIK_PUBLIC_DOMAIN` can be set in `.env.local` instead of `.env` (see {doc}`../environments/customizing`). + +Projects running Varnish are routed through Varnish automatically; no separate configuration is needed. + +## Cloudflare Tunnel Provider + +### Prerequisites + +- A Cloudflare account +- A domain (zone) on Cloudflare +- Docker + +### Setup + +1. Set the provider in `~/.warden/.env`: + + ```{code-block} bash + WARDEN_SHARE_PROVIDER=cloudflared + ``` + +2. Authenticate with Cloudflare: + + ```{code-block} bash + warden share login + ``` + + This opens a browser for Cloudflare authentication. On success a `cert.pem` is stored in `~/.warden/etc/cloudflared/`. + +3. Create a tunnel: + + ```{code-block} bash + warden share create [name] + ``` + + The tunnel name defaults to `warden`. This writes `WARDEN_CLOUDFLARED_TUNNEL_ID` into `~/.warden/.env`, and adds `WARDEN_SHARE_PROVIDER=cloudflared` to that file if it is not already set. + +4. Create the DNS record. In the Cloudflare dashboard, add a proxied CNAME record for the hostname (and for `*.hostname` if subdomains are used) pointing to `.cfargotunnel.com`. This can also be done with `cloudflared tunnel route dns`. Warden does not create this record. + +5. Start global services: + + ```{code-block} bash + warden svc up + ``` + +6. Set the public hostname in the project's `.env`: + + ```{code-block} bash + TRAEFIK_PUBLIC_DOMAIN=myproject.example.com + ``` + +7. Start the project: + + ```{code-block} bash + warden env up + ``` + +8. Check status: + + ```{code-block} bash + warden share status + ``` + + This prints the configured provider, the tunnel ID, whether the container is running, and the list of domains currently connected. + +### Configuration Regeneration + +The provider's ingress configuration is regenerated from the set of domains carrying the `dev.warden.share.domain` label on any running container. This happens on every `warden env up`, `warden env down`, `warden env start`, `warden env stop`, and on `warden svc up`. The share agent container is restarted only when the regenerated ingress list actually changed, so starting or stopping one project does not interrupt tunnels for other projects. + +`warden share update` forces a regeneration and restart. `warden share delete` removes the tunnel from Cloudflare. `warden share logout` removes all cloudflared credentials and configuration from `~/.warden/etc/cloudflared/`; if a tunnel is still configured it asks for confirmation first, since the tunnel would otherwise be left orphaned on the Cloudflare side. + +Cloudflared files live under `~/.warden/etc/cloudflared/`: `cert.pem` (Cloudflare account credential), the tunnel credentials file, and the generated `config.yml`. + +:::{note} +The generated tunnel configuration sets `noTLSVerify: true` on the connection between the share agent and Traefik. This is expected: it applies only to the internal Docker network segment, where the agent is trusting Warden's self-signed Traefik certificate. The public-facing leg of the connection is terminated with Cloudflare's own edge TLS certificate. +::: + +### Troubleshooting + +- **Warning about a missing tunnel on `warden svc up`**: `WARDEN_SHARE_PROVIDER` is set but no tunnel has been created yet. Run `warden share login` and `warden share create`. +- **404 from Cloudflare**: the DNS record is missing, or the project's domain is not in the generated ingress list. Check `warden share status` for the connected domains. +- **`TRAEFIK_PUBLIC_DOMAIN` rejected on `warden env up`**: the value must match a plain hostname pattern (letters, digits, hyphens, at least one dot). + +## Adding A Provider + +A share provider is added as `utils/share/.sh` plus a `docker-compose.share-.yml` file. The script must implement six functions: `shareProviderIsConfigured` (whether the provider has enough state to run), `shareProviderComposeFile` (path to the compose file to include), `shareProviderPreflight` (warnings shown on `svc up`), `shareProviderRegenerateConfig` (rewrite the provider's configuration from the current domain list), `shareProviderStatus` (output for `warden share status`), and `shareProviderCommand` (handling for any provider-specific subcommands). diff --git a/environments/customizing.md b/environments/customizing.md index 6e7f30d..c5aeba9 100644 --- a/environments/customizing.md +++ b/environments/customizing.md @@ -1,5 +1,9 @@ # Customizing An Environment +## Personal Overrides via `.env.local` + +Values in a project's `.env.local` file (typically git-ignored) override the same variable set in `.env`. `WARDEN_`, `TRAEFIK_` and `PHP_` prefixed variables are read from it. This is the place for a setting that is specific to one developer's machine and should not be committed, such as a personal `TRAEFIK_PUBLIC_DOMAIN` used with {doc}`../configuration/share`. + ## Version Customization via `.env` To configure your project with a non-default PHP version, add the following to the project's `.env` file and run `warden env up` to re-create the affected containers: diff --git a/index.md b/index.md index a43ba4f..6f38c3f 100644 --- a/index.md +++ b/index.md @@ -10,6 +10,7 @@ Under the hood `docker-compose` is used to control everything which Warden runs * Dnsmasq to serve DNS responses for `.test` domains eliminating manual editing of `/etc/hosts` * An SSH tunnel for connecting from Sequel Pro or TablePlus into any one of multiple running database containers. * Warden issued wildcard SSL certificates for running https on all local development domains. +* Optional sharing of a project to the public internet through a share provider such as Cloudflare Tunnel. * Full support for Magento 1, Magento 2, Laravel, Symfony 4, Shopware 6 on both macOS and Linux. * Ability to override, extend, or setup completely custom environment definitions on a per-project basis. diff --git a/services.md b/services.md index 0df0f95..5413427 100644 --- a/services.md +++ b/services.md @@ -19,6 +19,7 @@ The following options are available (with default values indicated): * `WARDEN_RESTART_POLICY=always` may be set to `no` to prevent Docker from restarting these service containers or any other valid [restart policy](https://docs.docker.com/config/containers/start-containers-automatically/#use-a-restart-policy) value. * `WARDEN_SERVICE_DOMAIN=warden.test` may be set to a domain of your choosing if so desired. Please note that this will not currently change network settings or alter `dnsmasq` configuration. Any TLD other than `test` will require DNS resolution be manually configured. * `WARDEN_PHPMYADMIN_ENABLE=1` may be set to `0` to disable the phpMyAdmin global service. +* `WARDEN_SHARE_PROVIDER` may be set to enable a share agent, such as `cloudflared`, that exposes projects to the public internet. See {doc}`configuration/share` for setup instructions. :::{warning} Setting ``TRAEFIK_LISTEN=0.0.0.0`` can be quite useful in some cases, but be aware that causing Traefik to listen for requests publicly poses a security risk when on public WiFi or networks otherwise outside of your control.