From 9f8bd0d47a948af24dbf3ff5852969a6d69466d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bajsarowicz?= Date: Sun, 22 Mar 2026 21:32:16 +0100 Subject: [PATCH 1/2] docs: document custom commands support Add Custom Commands section to the customizing page explaining how to create project-level and global custom commands using .cmd and .help files, including resolution order, example, and link to the Magento 2 template as a real-world reference. --- environments/customizing.md | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/environments/customizing.md b/environments/customizing.md index d5a936c..df9ab66 100644 --- a/environments/customizing.md +++ b/environments/customizing.md @@ -72,6 +72,49 @@ services: ``` There you can specify a custom Nginx configuration which will be included following the `.conf` files within the `/etc/nginx/available.d` directory: `include /etc/nginx/default.d/*.conf` +## Custom Commands + +Warden supports adding custom commands at both the project and global level. Each custom command consists of two files: + + * `.cmd` — the bash script that runs when you execute `warden ` + * `.help` — the help text displayed in `warden help` output (required for the command to appear in the help listing) + +### Command locations + + * **Project-level:** `/.warden/commands/` — available only within that project + * **Global:** `~/.warden/commands/` — available in all projects + +When a command name exists in multiple locations, the resolution order is: project → global → built-in. This means project commands can override global ones, and both can override built-in commands. + +### Example + +Create a project command that clears all Magento caches: + +`.warden/commands/flush.cmd`: +```bash +#!/usr/bin/env bash +[[ ! ${WARDEN_DIR} ]] && >&2 echo -e "\033[31mThis script is not intended to be run directly!\033[0m" && exit 1 + +warden env exec -T php-fpm bin/magento cache:flush +``` + +`.warden/commands/flush.help`: +```bash +#!/usr/bin/env bash +WARDEN_USAGE=$(cat < Date: Sun, 22 Mar 2026 22:40:12 +0100 Subject: [PATCH 2/2] docs: add Cloudflare Tunnel documentation --- configuration/cloudflare-tunnel.md | 124 +++++++++++++++++++++++++++++ index.md | 1 + services.md | 2 + 3 files changed, 127 insertions(+) create mode 100644 configuration/cloudflare-tunnel.md diff --git a/configuration/cloudflare-tunnel.md b/configuration/cloudflare-tunnel.md new file mode 100644 index 0000000..8f26845 --- /dev/null +++ b/configuration/cloudflare-tunnel.md @@ -0,0 +1,124 @@ +# Cloudflare Tunnel + +Warden integrates with [Cloudflare Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) to expose local development environments to the public internet. This is useful for: + +- Sharing work-in-progress with clients or teammates +- Testing webhooks from external services +- Mobile device testing on real domains +- QA review without deploying to staging + +## Prerequisites + +- A [Cloudflare account](https://dash.cloudflare.com/sign-up) +- A domain configured in Cloudflare (DNS managed by Cloudflare) + +## Setup + +### 1. Authenticate with Cloudflare + +```{code-block} bash +warden cf login +``` + +This opens your browser for Cloudflare authentication. A `cert.pem` file is saved to `~/.warden/etc/cloudflared/`. + +### 2. Create a tunnel + +```{code-block} bash +warden cf create +``` + +This creates a tunnel named `warden` (or pass a custom name: `warden cf create mytunnel`). The tunnel ID is saved to `~/.warden/.env` as `WARDEN_CLOUDFLARED_TUNNEL_ID`. + +### 3. Start global services + +```{code-block} bash +warden svc up +``` + +The `cloudflared` container starts automatically when `WARDEN_CLOUDFLARED_TUNNEL_ID` is set. + +### 4. Configure a project + +Add `TRAEFIK_PUBLIC_DOMAIN` to your project's `.env`: + +```{code-block} bash +TRAEFIK_PUBLIC_DOMAIN=myproject.example.com +``` + +### 5. Configure DNS in Cloudflare + +In the [Cloudflare dashboard](https://dash.cloudflare.com/), add a CNAME record pointing your domain to the tunnel: + +| Type | Name | Target | +|------|------|--------| +| CNAME | myproject | `.cfargotunnel.com` | +| CNAME | *.myproject | `.cfargotunnel.com` | + +Replace `` with your tunnel ID from `warden cf status`. + +### 6. Start the project + +```{code-block} bash +warden env up +``` + +Warden automatically regenerates the cloudflared config to include your project's domain. Your site is now accessible at `https://myproject.example.com`. + +## How It Works + +``` +Internet → Cloudflare Edge → cloudflared container → Traefik → nginx → php-fpm +``` + +1. **cloudflared** maintains a persistent connection to Cloudflare's edge network +2. Incoming requests for your domain are forwarded through the tunnel to the local **cloudflared** container +3. **cloudflared** routes the request to **Traefik** (the local reverse proxy) +4. **Traefik** matches the `Host` header to the correct project and forwards to **nginx** +5. **nginx** serves the request from **php-fpm** as usual + +The cloudflared configuration is automatically regenerated whenever you run `warden env up`, `warden env down`, `warden env start`, or `warden env stop`. + +## Configuration + +### Global (`~/.warden/.env`) + +| Variable | Description | +|----------|-------------| +| `WARDEN_CLOUDFLARED_TUNNEL_ID` | Tunnel UUID. Set automatically by `warden cf create`. When present, enables the cloudflared service. | + +### Project (`.env`) + +| Variable | Description | +|----------|-------------| +| `TRAEFIK_PUBLIC_DOMAIN` | Public domain for this project (e.g., `myproject.example.com`). When set, the project is exposed via the Cloudflare Tunnel. | + +## CLI Reference + +| Command | Description | +|---------|-------------| +| `warden cf login` | Authenticate with Cloudflare (opens browser) | +| `warden cf create [name]` | Create a new tunnel (default name: `warden`) | +| `warden cf delete` | Delete the tunnel from Cloudflare | +| `warden cf status` | Show tunnel status and connected domains | +| `warden cf update` | Force-regenerate cloudflared config and restart | +| `warden cf logout` | Remove all cloudflared credentials and config | + +## Troubleshooting + +### Tunnel not connecting + +1. Check the cloudflared container is running: `warden svc ps` +2. Check logs: `warden svc logs cloudflared` +3. Verify credentials exist: `ls ~/.warden/etc/cloudflared/` + +### Domain not routing + +1. Check the domain label is set: `docker inspect | grep cf.domain` +2. Verify the config was generated: `cat ~/.warden/etc/cloudflared/config.yml` +3. Force regenerate: `warden cf update` +4. Check DNS records in Cloudflare dashboard point to `.cfargotunnel.com` + +### Certificate errors + +The cloudflared-to-Traefik connection uses `noTLSVerify: true` because Traefik uses Warden's self-signed certificates. This is expected and only affects the local tunnel segment — the public-facing connection uses Cloudflare's edge certificates. diff --git a/index.md b/index.md index b6ec755..776e8cf 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. +* Cloudflare Tunnel integration for exposing local environments to the public internet. * 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 127a45a..e9bd05d 100644 --- a/services.md +++ b/services.md @@ -6,6 +6,7 @@ After running `warden svc up` for the first time following installation, the fol * [https://portainer.warden.test/](https://portainer.warden.test/) * [https://dnsmasq.warden.test/](https://dnsmasq.warden.test/) * [https://mailhog.warden.test/](https://mailhog.warden.test/) +* Cloudflare Tunnel (`warden cf status` — when configured) ## Customizable Settings @@ -16,6 +17,7 @@ The following options are available (with default values indicated): * `TRAEFIK_LISTEN=127.0.0.1` may be set to `0.0.0.0` for example to have Traefik accept connections from other devices on the local network. * `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_CLOUDFLARED_TUNNEL_ID` is set automatically by `warden cf create` and enables the Cloudflare Tunnel service. See {doc}`configuration/cloudflare-tunnel` 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.