Repository: ddev/ddev
Pull request #6607 (2024-10-09 21:04:35)

docs: sort commands alphabetically, add missing aliases
## The Issue

After `ddev get` was renamed to `ddev add-on`, it was not moved in the docs.
And when I added `ddev dotenv`, I saw `ddev add-on` and simply added my commands right after it.

## How This PR Solves The Issue

Sorts commands alphabetically.
Adds missing aliases from `ddev aliases` to the docs.

## Manual Testing Instructions

See https://ddev--6607.org.readthedocs.build/en/6607/users/usage/commands/

## Automated Testing Overview

<!-- Please describe the tests introduced by this PR, or explain why no tests are needed. -->

## Release/Deployment Notes

<!-- Does this affect anything else or have ramifications for other code? Does anything have to be done on deployment? -->



Patch:
diff --git a/docs/content/users/debugging-profiling/blackfire-profiling.md b/docs/content/users/debugging-profiling/blackfire-profiling.md
index 9dc12a005..1ece7d89c 100644
--- a/docs/content/users/debugging-profiling/blackfire-profiling.md
+++ b/docs/content/users/debugging-profiling/blackfire-profiling.md
@@ -19,15 +19,15 @@ The Blackfire CLI is built into the web container, so you don’t need to instal
 1. Add the `BLACKFIRE_SERVER_ID`, `BLACKFIRE_SERVER_TOKEN`, `BLACKFIRE_CLIENT_ID`, and `BLACKFIRE_CLIENT_TOKEN` environment variables to `~/.ddev/global_config.yaml` via the `web_environment` key:
 
     ```yaml
-      web_environment:
-      - OTHER_ENV=something
-      - BLACKFIRE_SERVER_ID=dde5f66d-xxxxxx
-      - BLACKFIRE_SERVER_TOKEN=09b0ec-xxxxx
-      - BLACKFIRE_CLIENT_ID=f5e88b7e-xxxxx
-      - BLACKFIRE_CLIENT_TOKEN=00cee15-xxxxx1
+    web_environment:
+        - OTHER_ENV=something
+        - BLACKFIRE_SERVER_ID=dde5f66d-xxxxxx
+        - BLACKFIRE_SERVER_TOKEN=09b0ec-xxxxx
+        - BLACKFIRE_CLIENT_ID=f5e88b7e-xxxxx
+        - BLACKFIRE_CLIENT_TOKEN=00cee15-xxxxx1
     ```
 
-    You can also do this with `ddev config global --web-environment-add="BLACKFIRE_SERVER_ID=<id>,BLACKFIRE_SERVER_TOKEN=<token>,BLACKFIRE_CLIENT_ID=<id>,BLACKFIRE_CLIENT_TOKEN=<token>"`, but any existing environment variables will be deleted.
+    You can also do this with `ddev config global --web-environment-add="BLACKFIRE_SERVER_ID=<id>,BLACKFIRE_SERVER_TOKEN=<token>,BLACKFIRE_CLIENT_ID=<id>,BLACKFIRE_CLIENT_TOKEN=<token>"`.
   
 2. [`ddev start`](../usage/commands.md#start).
 3. `ddev blackfire on`.
diff --git a/docs/content/users/extend/customization-extendibility.md b/docs/content/users/extend/customization-extendibility.md
index 5c181d764..36c2a40aa 100644
--- a/docs/content/users/extend/customization-extendibility.md
+++ b/docs/content/users/extend/customization-extendibility.md
@@ -37,16 +37,16 @@ You can set custom environment variables in several places:
 
     ```yaml
     web_environment:
-    - MY_ENV_VAR=someval
-    - MY_OTHER_ENV_VAR=someotherval
+        - MY_ENV_VAR=someval
+        - MY_OTHER_ENV_VAR=someotherval
     ```
 
 4. The project’s [`web_environment`](../configuration/config.md#web_environment) setting in `.ddev/config.yaml` or `.ddev/config.*.yaml`:
 
     ```yaml
     web_environment:
-    - MY_ENV_VAR=someval
-    - MY_OTHER_ENV_VAR=someotherval
+        - MY_ENV_VAR=someval
+        - MY_OTHER_ENV_VAR=someotherval
     ```
 
 If you’d rather use the CLI to set the project or global `web_environment` value, you can use the [`ddev config`](../usage/commands.md#config) command:
diff --git a/docs/content/users/install/ddev-installation.md b/docs/content/users/install/ddev-installation.md
index 46bd3c683..a2b183eb6 100644
--- a/docs/content/users/install/ddev-installation.md
+++ b/docs/content/users/install/ddev-installation.md
@@ -404,18 +404,18 @@ Once you’ve [installed a Docker provider](docker-installation.md), you’re re
 
     You can expose ports via the `ports` setting, which is usually not recommended if you work locally due to port conflicts. But you can load these additional Docker compose files only when Codespaces is detected. See [Defining Additional Services](./../extend/custom-compose-files.md#docker-composeyaml-examples) for more information. 
 
-    ```
+    ```yaml
     services:
         web:
             ports:
-            - "5174:5174"
+                - "5174:5174"
     ```
 
     ### Default environment variables
 
     Codespace instances already provide some [default environment values](https://docs.github.com/en/codespaces/developing-in-codespaces/default-environment-variables-for-your-codespace). You can inherit and inject them in your `.ddev/config.yaml`:
     
-    ```
+    ```yaml
     web_environment: 
         - CODESPACES
         - CODESPACE_NAME
diff --git a/docs/content/users/providers/acquia.md b/docs/content/users/providers/acquia.md
index b180182f0..12bfadaac 100644
--- a/docs/content/users/providers/acquia.md
+++ b/docs/content/users/providers/acquia.md
@@ -9,20 +9,32 @@ DDEV’s Acquia integration pulls database and files from an existing project in
 1. Get your Acquia API token from *Account Settings* → *API Tokens*.
 2. Make sure you’ve added your SSH key to your Acquia account in *Account Settings* → *SSH Keys*.
 3. Run [`ddev auth ssh`](../usage/commands.md#auth-ssh). (Typically once per DDEV session, not every pull.)
-4. In `~/.ddev/global_config.yaml` (or the project `config.yaml`), add or update the [`web_environment`](../configuration/config.md#web_environment) section with the API keys:
+4. In `~/.ddev/global_config.yaml` add or update the [`web_environment`](../configuration/config.md#web_environment) section with the API keys:
 
-   ```yaml
-   web_environment:
-   - ACQUIA_API_KEY=xxxxxxxx
-   - ACQUIA_API_SECRET=xxxxx
-   ```
+    ```yaml
+    web_environment:
+        - ACQUIA_API_KEY=xxxxxxxx
+        - ACQUIA_API_SECRET=xxxxx
+    ```
+
+    You can also do this with:
+
+    ```bash
+    ddev config global --web-environment-add="ACQUIA_API_KEY=xxxxxxxx,ACQUIA_API_SECRET=xxxxx"
+    ```
 
 5. In the project `.ddev/config.yaml` add the `ACQUIA_ENVIRONMENT_ID` environment variable:
 
-   ```yaml
-   web_environment:
-   - ACQUIA_ENVIRONMENT_ID=yoursite.dev
-   ```
+    ```yaml
+    web_environment:
+        - ACQUIA_ENVIRONMENT_ID=yoursite.dev
+    ```
+
+    You can also do this with:
+
+    ```bash
+    ddev config --web-environment-add="ACQUIA_ENVIRONMENT_ID=yoursite.dev"
+    ```
 
 6. Run [`ddev restart`](../usage/commands.md#restart).
 7. Use `ddev pull acquia` to pull the project database and files.
diff --git a/docs/content/users/providers/index.md b/docs/content/users/providers/index.md
index 40c915389..dffb49337 100644
--- a/docs/content/users/providers/index.md
+++ b/docs/content/users/providers/index.md
@@ -1,6 +1,6 @@
 # Hosting Provider Integration
 
-DDEV offers hosting provider integration and sample integrations for [Pantheon](https://pantheon.io), [Platform.sh](https://platform.sh) and [Acquia](https://www.acquia.com) hosting, along with other examples.
+DDEV offers hosting provider integration and sample integrations for [Pantheon](https://pantheon.io), [Platform.sh](https://platform.sh), [Upsun](https://upsun.com/), [Lagoon](https://lagoon.sh/) and [Acquia](https://www.acquia.com) hosting, along with other examples.
 
 Hosting provider integration allows connecting with your upstream hosting. `ddev pull <provider>` downloads and `ddev push <provider>` uploads the **database** and the **user-generated files** to an upstream provider. It does *not* push (deploy) or pull your code. Your code should be under version control in for example Git.
 
@@ -14,17 +14,28 @@ DDEV also provides the `push` command to push database and files to upstream. Th
 
 Each provider recipe is a YAML file that can have whatever name you want. The examples are mostly named after the hosting providers, but they could be named `upstream.yaml` or `live.yaml`, so you could `ddev pull upstream` or `ddev pull live`. If you wanted different upstream environments to pull from, you could name one “prod” and one “dev” and `ddev pull prod` and `ddev pull dev`.
 
-[Recipes](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/) are provided for [Acquia](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/acquia.yaml), [Local files](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/localfile.yaml.example) (like Dropbox, for example), [Pantheon](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/pantheon.yaml.example), [Platform.sh](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/platform.yaml), and [rsync](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/rsync.yaml.example). We know you’ll find improvements to these examples and will have lots to contribute for other hosting providers, and we look forward to your contributions as pull requests here or in [ddev-contrib](https://github.com/ddev/ddev-contrib).
+[Recipes](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/) are provided for:
+
+- [Acquia](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/acquia.yaml)
+- [Git](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/git.yaml.example)
+- [Lagoon](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/lagoon.yaml)
+- [Local files](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/localfile.yaml.example) (like Dropbox, for example)
+- [Pantheon](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/pantheon.yaml.example)
+- [Platform.sh](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/platform.yaml)
+- [rsync](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/rsync.yaml.example)
+- [Upsun](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/upsun.yaml)
+
+We know you’ll find improvements to these examples and will have lots to contribute for other hosting providers, and we look forward to your contributions as pull requests here or in [ddev-contrib](https://github.com/ddev/ddev-contrib).
 
 Each provider recipe is a file named `<provider>.yaml` and consists of several mostly-optional stanzas:
 
-* `environment_variables`: Environment variables will be created in the web container for each of these during pull or push operations. They’re used to provide context (project ID, environment name, etc.) for each of the other stanzas. This stanza is not used in more recent hosting integrations, since providing the environment variables in `config.yaml` or via `ddev pull xxx --environment=VARIABLE=value` is preferred.
-* `db_pull_command`: A script that determines how DDEV should obtain a database. Its job is to create a gzipped database dump in `/var/www/html/.ddev/.downloads/db.sql.gz`. This is optional; if nothing has to be done to obtain the database dump, this step can be omitted.
-* `db_import_command`: (optional) A script that imports the downloaded database. This is for advanced usages like multiple databases. The default behavior only imports a single database into the `db` database. The [localfile example](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/localfile.yaml.example) uses this technique.
-* `files_pull_command`: A script that determines how DDEV can get user-generated files from upstream. Its job is to copy the files from upstream to `/var/www/html/.ddev/.downloads/files`. If nothing has to be done to obtain the files, this step can run `true`.
-* `files_import_command`: (optional) A script that imports the downloaded files. There are a number of situations where it’s messy to push a directory of files around, and one can put it directly where it’s needed. The [localfile example](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/localfile.yaml.example) uses this technique.
-* `db_push_command`: A script that determines how DDEV should push a database. Its job is to take a gzipped database dump from `/var/www/html/.ddev/.downloads/db.sql.gz` and load it on the hosting provider.
-* `files_push_command`: A script that determines how DDEV push user-generated files to upstream. Its job is to copy the files from the project’s user-files directories (`$DDEV_FILES_DIRS`) to the correct places on the upstream provider.
+- `environment_variables`: Environment variables will be created in the web container for each of these during pull or push operations. They’re used to provide context (project ID, environment name, etc.) for each of the other stanzas. This stanza is not used in more recent hosting integrations, since providing the environment variables in `config.yaml` or via `ddev pull xxx --environment=VARIABLE=value` is preferred.
+- `db_pull_command`: A script that determines how DDEV should obtain a database. Its job is to create a gzipped database dump in `/var/www/html/.ddev/.downloads/db.sql.gz`. This is optional; if nothing has to be done to obtain the database dump, this step can be omitted.
+- `db_import_command`: (optional) A script that imports the downloaded database. This is for advanced usages like multiple databases. The default behavior only imports a single database into the `db` database. The [localfile example](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/localfile.yaml.example) uses this technique.
+- `files_pull_command`: A script that determines how DDEV can get user-generated files from upstream. Its job is to copy the files from upstream to `/var/www/html/.ddev/.downloads/files`. If nothing has to be done to obtain the files, this step can run `true`.
+- `files_import_command`: (optional) A script that imports the downloaded files. There are a number of situations where it’s messy to push a directory of files around, and one can put it directly where it’s needed. The [localfile example](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/localfile.yaml.example) uses this technique.
+- `db_push_command`: A script that determines how DDEV should push a database. Its job is to take a gzipped database dump from `/var/www/html/.ddev/.downloads/db.sql.gz` and load it on the hosting provider.
+- `files_push_command`: A script that determines how DDEV push user-generated files to upstream. Its job is to copy the files from the project’s user-files directories (`$DDEV_FILES_DIRS`) to the correct places on the upstream provider.
 
 The [environment variables provided to custom commands](../extend/custom-commands.md#environment-variables-provided) are also available for use in these recipes.
 
@@ -32,8 +43,8 @@ There are [hooks](../configuration/hooks.md) available to execute commands befor
 
 ## Example Integrations and Hints
 
-* All of the [supplied integrations](https://github.com/ddev/ddev/tree/master/pkg/ddevapp/dotddev_assets/providers) are examples of what you can do.
-* You can name a provider anything you want. For example, an Acquia integration doesn’t have to be named “acquia”, it can be named “upstream”. This is a great technique for [downloading a particular multisite](https://stackoverflow.com/a/68553116/215713).
+- All of the [supplied integrations](https://github.com/ddev/ddev/tree/master/pkg/ddevapp/dotddev_assets/providers) are examples of what you can do.
+- You can name a provider anything you want. For example, an Acquia integration doesn’t have to be named “acquia”, it can be named “upstream”. This is a great technique for [downloading a particular multisite](https://stackoverflow.com/a/68553116/215713).
 
 ## Provider Debugging
 
diff --git a/docs/content/users/providers/lagoon.md b/docs/content/users/providers/lagoon.md
index 20e5b6059..80047f552 100644
--- a/docs/content/users/providers/lagoon.md
+++ b/docs/content/users/providers/lagoon.md
@@ -5,7 +5,20 @@ DDEV provides integration with [Lagoon](https://lagoon.sh/), allowing users to q
 ## Lagoon Per-Project Configuration
 
 1. Check out the Lagoon project and configure it by running [`ddev config`](../usage/commands.md#config). You’ll want to run [`ddev start`](../usage/commands.md#start) and make sure the basic functionality is working.
-2. Add `LAGOON_PROJECT` and `LAGOON_ENVIRONMENT` variables to your project using `'web_environment'` in its YAML configuration or a `.ddev/.env` file. For example, run `ddev config --web-environment-add="LAGOON_PROJECT=<project-name>,LAGOON_ENVIRONMENT=<environment-name>"`.
+2. Add `LAGOON_PROJECT` and `LAGOON_ENVIRONMENT` variables to your project using `'web_environment'` in its YAML configuration or a `.ddev/.env` file. For example:
+
+    ```yaml
+    web_environment:
+        - LAGOON_PROJECT=<project-name>
+        - LAGOON_ENVIRONMENT=<environment-name>
+    ```
+
+    You can also do this with:
+
+    ```bash
+    ddev config --web-environment-add="LAGOON_PROJECT=<project-name>,LAGOON_ENVIRONMENT=<environment-name>"
+    ```
+
 3. Configure an [SSH key](https://docs.lagoon.sh/using-lagoon-advanced/ssh/) for your Lagoon user.
 4. Run `ddev auth ssh` to make your SSH key available in the project’s web container.
 5. Run [`ddev restart`](../usage/commands.md#restart).
diff --git a/docs/content/users/providers/pantheon.md b/docs/content/users/providers/pantheon.md
index bd2bf4b0e..c493f8c06 100644
--- a/docs/content/users/providers/pantheon.md
+++ b/docs/content/users/providers/pantheon.md
@@ -9,12 +9,13 @@ DDEV’s Pantheon integration pulls an existing backup from an existing Pantheon
 If you have DDEV installed, and have an active Pantheon account with an active site, you can follow this guide to spin up a Pantheon project locally.
 
 1. Get your Pantheon machine token:
-   a. Log in to your Pantheon Dashboard and [Generate a Machine Token](https://pantheon.io/docs/machine-tokens/) for DDEV to use.
-   b. Add the API token to the `web_environment` section in your global DDEV configuration at `~/.ddev/global_config.yaml`.<!-- markdownlint-disable-next-line -->
-   ```
-   web_environment:
-   - TERMINUS_MACHINE_TOKEN=abcdeyourtoken
-   ```
+    1. Log in to your Pantheon Dashboard and [Generate a Machine Token](https://pantheon.io/docs/machine-tokens/) for DDEV to use.
+    2. Add the API token to the `web_environment` section in your global DDEV configuration at `~/.ddev/global_config.yaml`.
+
+        ```yaml
+        web_environment:
+            - TERMINUS_MACHINE_TOKEN=your_token
+        ```
 
 2. Choose a Pantheon site and environment you want to use with DDEV. You can usually use the site name, but in some environments you may need the site ID, which is the long third component of your site dashboard URL. So if the site dashboard is at `https://dashboard.pantheon.io/sites/009a2cda-2c22-4eee-8f9d-96f017321555#dev/`, the site ID is `009a2cda-2c22-4eee-8f9d-96f017321555`.
 
diff --git a/docs/content/users/providers/platform.md b/docs/content/users/providers/platform.md
index d38545d25..c727d621d 100644
--- a/docs/content/users/providers/platform.md
+++ b/docs/content/users/providers/platform.md
@@ -14,10 +14,16 @@ You need to obtain and configure an API token first. This is only needed once.
 1. Login to the Platform.sh Dashboard and go to *Account* → *API Tokens*. Create an API token DDEV can use.
 2. Add the API token to the `web_environment` section in your global DDEV configuration at `~/.ddev/global_config.yaml`:
 
-```yaml
-web_environment:
-  - PLATFORMSH_CLI_TOKEN=abcdeyourtoken
-```
+    ```yaml
+    web_environment:
+        - PLATFORMSH_CLI_TOKEN=abcdeyourtoken
+    ```
+
+    You can also do this with:
+
+    ```bash
+    ddev config global --web-environment-add="PLATFORMSH_CLI_TOKEN=abcdeyourtoken"`
+    ```
 
 ## Platform.sh Per-Project Configuration
 
@@ -28,8 +34,8 @@ web_environment:
 
         ```yaml
         web_environment:
-        - PLATFORM_PROJECT=nf4amudfn23biyourproject
-        - PLATFORM_ENVIRONMENT=main
+            - PLATFORM_PROJECT=nf4amudfn23biyourproject
+            - PLATFORM_ENVIRONMENT=main
         ```
 
     * Or with a command from your terminal:
@@ -50,8 +56,8 @@ If your environment contains more than one app, add `PLATFORM_APP` variable to y
 
     ```yaml
     web_environment:
-    - ...
-    - PLATFORM_APP=app
+        - ...
+        - PLATFORM_APP=app
     ```
 
 * Or with a command from your terminal:
@@ -68,13 +74,13 @@ If your project has multiple databases, they’ll all be pulled into DDEV with t
 
 You can designate the primary database using the `PLATFORM_PRIMARY_RELATIONSHIP` environment variable:
 
-```
+```bash
 ddev config --web-environment-add="PLATFORM_PRIMARY_RELATIONSHIP=main"
 ```
 
 You can also do the same thing by running `ddev pull platform` and using the `--environment` flag:
 
-```
+```bash
 ddev pull platform --environment="PLATFORM_PRIMARY_RELATIONSHIP=main"
 ```
 
diff --git a/docs/content/users/providers/upsun.md b/docs/content/users/providers/upsun.md
index a93e5add0..032f8e156 100644
--- a/docs/content/users/providers/upsun.md
+++ b/docs/content/users/providers/upsun.md
@@ -11,10 +11,16 @@ You need to obtain and configure an API token first. This only needs to be done
 1. Login to the Upsun Dashboard and go to *My Profile* → *API Tokens*. Create an API token DDEV can use.
 2. Add the API token to the `web_environment` section in your global DDEV configuration at `~/.ddev/global_config.yaml`:
 
-```yaml
-web_environment:
-  - UPSUN_CLI_TOKEN=abcdeyourtoken
-```
+    ```yaml
+    web_environment:
+        - UPSUN_CLI_TOKEN=abcdeyourtoken
+    ```
+
+    You can also do this with:
+
+    ```bash
+    ddev config global --web-environment-add="UPSUN_CLI_TOKEN=abcdeyourtoken"
+    ```
 
 ## Upsun Per-Project Configuration
 
@@ -25,8 +31,8 @@ web_environment:
 
         ```yaml
         web_environment:
-        - UPSUN_PROJECT=nf4amudfn23biyourproject
-        - UPSUN_ENVIRONMENT=main
+            - UPSUN_PROJECT=nf4amudfn23biyourproject
+            - UPSUN_ENVIRONMENT=main
         ```
 
     * Or with a command from your terminal:
diff --git a/docs/content/users/usage/cms-settings.md b/docs/content/users/usage/cms-settings.md
index 4af0a12f7..b9eaa8d8d 100644
--- a/docs/content/users/usage/cms-settings.md
+++ b/docs/content/users/usage/cms-settings.md
@@ -93,10 +93,10 @@ $settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml'
 
         ```yaml
         web_environment:
-          # Make DDEV Drush shell PIDs last for entire life of the container
-          # so `ddev drush site:set @alias` persists for all Drush connections.
-          # https://chrisfromredfin.dev/posts/drush-use-ddev/
-          - DRUSH_SHELL_PID=PERMANENT
+            # Make DDEV Drush shell PIDs last for entire life of the container
+            # so `ddev drush site:set @alias` persists for all Drush connections.
+            # https://chrisfromredfin.dev/posts/drush-use-ddev/
+            - DRUSH_SHELL_PID=PERMANENT
         ```
 
 ### TYPO3 Specifics
@@ -111,7 +111,7 @@ Since TYPO3 9.5 you have to setup a `Site Configuration` for each site you like
 
 ```yaml
 web_environment:
-- TYPO3_CONTEXT=Development/DDEV
+    - TYPO3_CONTEXT=Development/DDEV
 ```
 
 This variable will be available after the project start or restart.
diff --git a/docs/content/users/usage/commands.md b/docs/content/users/usage/commands.md
index 1a09a89a7..ca9cb9905 100644
--- a/docs/content/users/usage/commands.md
+++ b/docs/content/users/usage/commands.md
@@ -60,6 +60,104 @@ Two flags are available for every command:
 
 ---
 
+## `add-on`
+
+*Aliases: `addon`, `add-ons`, `addons`.*
+
+[Add-on](../extend/additional-services.md) commands.
+
+Environment variables:
+
+* `DDEV_GITHUB_TOKEN`: A [GitHub token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) may be used for `ddev add-on` requests (which result in GitHub API queries). It's unusual for casual users to need this, but if you're doing lots of `ddev add-on` requests you may run into rate limiting. The token you use requires no privileges at all. Example:
+
+```bash
+export DDEV_GITHUB_TOKEN=<your github token>
+ddev add-on list --all
+```
+
+### `add-on get`
+
+*Alias: `add-on install`.*
+
+Download an add-on (service, provider, etc.).
+
+Flags:
+
+* `--project <projectName>`: Specify a project to install the add-on into. Defaults to checking for a project in the current directory.
+* `--version <version>`: Specify a version to download
+* `--verbose`, `-v`: Output verbose error information with Bash `set -x` (default `false`)
+
+Example:
+
+```shell
+# Download the official Redis add-on
+ddev add-on get ddev/ddev-redis
+
+# Get debug info about `ddev add-on get` failure
+ddev add-on get ddev/ddev-redis --verbose
+
+# Download the official Redis add-on, version v1.0.4
+ddev add-on get ddev/ddev-redis --version v1.0.4
+
+# Download the Drupal Solr add-on from its v1.2.3 release tarball
+ddev add-on get https://github.com/ddev/ddev-drupal-solr/archive/refs/tags/v1.2.3.tar.gz
+
+# Copy an add-on available in another directory
+ddev add-on get /path/to/package
+
+# Copy an add-on from a tarball in another directory
+ddev add-on get /path/to/tarball.tar.gz
+
+# Download the official Redis add-on and install it into a project named "my-project"
+ddev add-on get ddev/ddev-redis --project my-project
+```
+
+In general, you can run `ddev add-on get` multiple times without doing any damage. Updating an add-on can be done by running `ddev add-on get <add-on-name>`. If you have changed an add-on file and removed the `#ddev-generated` marker in the file, that file will not be touched and DDEV will let you know about it.
+
+### `add-on remove`
+
+Remove an installed add-on. Accepts the full add-on name, the short name of the repository, or with owner/repository format.
+
+Flags:
+
+* `--project <projectName>`: Specify a project to remove the add-on from. Defaults to checking for a project in the current directory.
+* `--verbose`, `-v`: Output verbose error information with Bash `set -x` (default `false`)
+
+Example:
+
+```shell
+ddev add-on remove redis
+ddev add-on remove ddev-redis
+ddev add-on remove ddev/ddev-redis
+ddev add-on remove ddev/ddev-redis --project my-project
+```
+
+### `add-on list`
+
+Download an add-on (service, provider, etc.).
+
+Flags:
+
+* `--all`: List unofficial *and* official add-ons. (default `true`)
+* `--installed`: List installed add-ons
+* `--project <projectName>`: Specify a project to remove the add-on from. Can only be used with the `--installed` flag. Defaults to checking for a project in the current directory.
+
+Example:
+
+```shell
+# List official add-ons
+ddev add-on list
+
+# List official and third-party add-ons
+ddev add-on list --all
+
+# List installed add-ons
+ddev add-on list --installed
+
+# List installed add-ons for a specific project
+ddev add-on list --installed --project my-project
+```
+
 ## `aliases`
 
 Shows all aliases for each command in the current context (global or project).
@@ -69,6 +167,17 @@ Shows all aliases for each command in the current context (global or project).
 ddev aliases
 ```
 
+## `artisan`
+
+*Alias: `art`.*
+
+Run the `artisan` command; available only in projects of type `laravel`, and only available if `artisan` is in the project root.
+
+```shell
+# Show all artisan subcommands
+ddev artisan list
+```
+
 ## `auth`
 
 Authentication commands.
@@ -88,17 +197,6 @@ Flags:
 
 * `--ssh-key-path`, `-d`: Full path to SSH key directory.
 
-## `artisan`
-
-*Aliases: `art`.*
-
-Run the `artisan` command; available only in projects of type `laravel`, and only available if `artisan` is in the project root.
-
-```shell
-# Show all artisan subcommands
-ddev artisan list
-```
-
 ## `blackfire`
 
 Enable or disable [Blackfire profiling](../debugging-profiling/blackfire-profiling.md) (global shell web container command).
@@ -446,7 +544,7 @@ ddev debug nfsmount
 
 ### `debug rebuild`
 
-*Aliases: `debug refresh`.*
+*Alias: `debug refresh`.*
 
 Rebuilds the project’s Docker cache with verbose output.
 
@@ -564,6 +662,47 @@ ddev describe
 ddev describe my-project
 ```
 
+## `dotenv`
+
+Commands for managing the contents of `.env` files.
+
+### `dotenv get`
+
+Get the value of an environment variable from a .env file. Provide the path relative to the project root when specifying the file.
+
+Example:
+
+```shell
+# Get the value of APP_KEY from the $DDEV_APPROOT/.env file
+ddev dotenv get .env --app-key
+
+# Get the value of ENV_KEY from the $DDEV_APPROOT/.ddev/.env file
+ddev dotenv get .ddev/.env --env-key
+```
+
+### `dotenv set`
+
+*Alias: `dotenv add`.*
+
+Create or update a `.env` file with values specified via long flags from the command line.
+Flags in the format `--env-key=value` will be converted to environment variable names
+like `ENV_KEY="value"`. The .env file should be named `.env` or `.env.<servicename>` or `.env.<something>`
+All environment variables can be used and expanded in `.ddev/docker-compose.*.yaml` files.
+Provide the path relative to the project root when specifying the file.
+
+Example:
+
+```shell
+# Create or update $DDEV_APPROOT/.env file with APP_KEY="value"
+ddev dotenv set .env --app-key=value
+
+# Create or update $DDEV_APPROOT/.ddev/.env file with EXTRA="value" and ANOTHER_KEY="extra value"
+ddev dotenv set .ddev/.env --extra value --another-key "extra value"
+
+# Create or update $DDEV_APPROOT/.ddev/.env.redis file with REDIS_TAG="7-bookworm"
+ddev dotenv set .ddev/.env.redis --redis-tag 7-bookworm
+```
+
 ## `drush`
 
 Run the `drush` command; available only in projects of type `drupal*`, and only available if `drush` is in the project. On projects of type `drupal`, `drush` should be installed in the project itself, (`ddev composer require drush/drush`). On projects of type `drupal7` `drush` 8 is provided by DDEV.
@@ -631,139 +770,6 @@ ddev export-db > /tmp/db.sql.gz
 ddev export-db my-project --gzip=false --file=/tmp/my-project.sql
 ```
 
-## `add-on`
-
-[Add-on](../extend/additional-services.md) commands.
-
-Environment variables:
-
-* `DDEV_GITHUB_TOKEN`: A [GitHub token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) may be used for `ddev add-on` requests (which result in GitHub API queries). It's unusual for casual users to need this, but if you're doing lots of `ddev add-on` requests you may run into rate limiting. The token you use requires no privileges at all. Example:
-
-```bash
-export DDEV_GITHUB_TOKEN=<your github token>
-ddev add-on list --all
-```
-
-### `add-on get`
-
-Download an add-on (service, provider, etc.).
-
-Flags:
-
-* `--project <projectName>`: Specify a project to install the add-on into. Defaults to checking for a project in the current directory.
-* `--version <version>`: Specify a version to download
-* `--verbose`, `-v`: Output verbose error information with Bash `set -x` (default `false`)
-
-Example:
-
-```shell
-# Download the official Redis add-on
-ddev add-on get ddev/ddev-redis
-
-# Get debug info about `ddev add-on get` failure
-ddev add-on get ddev/ddev-redis --verbose
-
-# Download the official Redis add-on, version v1.0.4
-ddev add-on get ddev/ddev-redis --version v1.0.4
-
-# Download the Drupal Solr add-on from its v1.2.3 release tarball
-ddev add-on get https://github.com/ddev/ddev-drupal-solr/archive/refs/tags/v1.2.3.tar.gz
-
-# Copy an add-on available in another directory
-ddev add-on get /path/to/package
-
-# Copy an add-on from a tarball in another directory
-ddev add-on get /path/to/tarball.tar.gz
-
-# Download the official Redis add-on and install it into a project named "my-project"
-ddev add-on get ddev/ddev-redis --project my-project
-```
-
-In general, you can run `ddev add-on get` multiple times without doing any damage. Updating an add-on can be done by running `ddev add-on get <add-on-name>`. If you have changed an add-on file and removed the `#ddev-generated` marker in the file, that file will not be touched and DDEV will let you know about it.
-
-### `add-on remove`
-
-Remove an installed add-on. Accepts the full add-on name, the short name of the repository, or with owner/repository format.
-
-Flags:
-
-* `--project <projectName>`: Specify a project to remove the add-on from. Defaults to checking for a project in the current directory.
-* `--verbose`, `-v`: Output verbose error information with Bash `set -x` (default `false`)
-
-Example:
-
-```shell
-ddev add-on remove redis
-ddev add-on remove ddev-redis
-ddev add-on remove ddev/ddev-redis
-ddev add-on remove ddev/ddev-redis --project my-project
-```
-
-### `add-on list`
-
-Download an add-on (service, provider, etc.).
-
-Flags:
-
-* `--all`: List unofficial *and* official add-ons. (default `true`)
-* `--installed`: List installed add-ons
-* `--project <projectName>`: Specify a project to remove the add-on from. Can only be used with the `--installed` flag. Defaults to checking for a project in the current directory.
-
-Example:
-
-```shell
-# List official add-ons
-ddev add-on list
-
-# List official and third-party add-ons
-ddev add-on list --all
-
-# List installed add-ons
-ddev add-on list --installed
-
-# List installed add-ons for a specific project
-ddev add-on list --installed --project my-project
-```
-
-## `dotenv`
-
-Commands for managing the contents of `.env` files.
-
-### `dotenv get`
-
-Get the value of an environment variable from a .env file. Provide the path relative to the project root when specifying the file.
-
-Example:
-
-```shell
-# Get the value of APP_KEY from the $DDEV_APPROOT/.env file
-ddev dotenv get .env --app-key
-
-# Get the value of ENV_KEY from the $DDEV_APPROOT/.ddev/.env file
-ddev dotenv get .ddev/.env --env-key
-```
-
-### `dotenv set`
-
-Create or update a `.env` file with values specified via long flags from the command line.
-Flags in the format `--env-key=value` will be converted to environment variable names
-like `ENV_KEY="value"`. The .env file should be named `.env` or `.env.<servicename>` or `.env.<something>`
-All environment variables can be used and expanded in `.ddev/docker-compose.*.yaml` files.
-Provide the path relative to the project root when specifying the file.
-
-Example:
-
-```shell
-# Create or update $DDEV_APPROOT/.env file with APP_KEY="value"
-ddev dotenv set .env --app-key=value
-
-# Create or update $DDEV_APPROOT/.ddev/.env file with EXTRA="value" and ANOTHER_KEY="extra value"
-ddev dotenv set .ddev/.env --extra value --another-key "extra value"
-
-# Create or update $DDEV_APPROOT/.ddev/.env.redis file with REDIS_TAG="7-bookworm"
-ddev dotenv set .ddev/.env.redis --redis-tag 7-bookworm
-```
-
 ## `heidisql`
 
 Open [HeidiSQL](https://www.heidisql.com/) with the current project’s database (global shell host container command). This command is only available if `Heidisql.exe` is installed as `C:\Program Files\HeidiSQL\Heidisql.exe`.
@@ -952,6 +958,15 @@ ddev logs -s db
 ddev logs -s db my-project
 ```
 
+## `magento`
+
+Run the `magento` command; available only in projects of type `magento2`, and only works if `bin/magento` is in the project.
+
+```shell
+# Show all magento subcommands
+ddev magento list
+```
+
 ## `mailpit`
 
 Launch a browser with mailpit for the current project (global shell host container command).
@@ -963,15 +978,6 @@ Example:
 ddev mailpit
 ```
 
-## `magento`
-
-Run the `magento` command; available only in projects of type `magento2`, and only works if `bin/magento` is in the project.
-
-```shell
-# Show all magento subcommands
-ddev magento list
-```
-
 ## `mutagen`
 
 Commands for [Mutagen](../install/performance.md#mutagen) status and sync, etc.
@@ -1019,6 +1025,8 @@ ddev mutagen reset my-project
 
 ### `mutagen status`
 
+*Alias: `mutagen st`.*
+
 Shows Mutagen sync status.
 
 Flags:
@@ -1452,6 +1460,8 @@ ddev ssh -d /var/www/html
 
 ## `start`
 
+*Alias: `add`*.
+
 Start a DDEV project.
 
 Flags:
diff --git a/markdown-link-check.json b/markdown-link-check.json
index d434f65b4..c12eb3b87 100644
--- a/markdown-link-check.json
+++ b/markdown-link-check.json
@@ -65,7 +65,11 @@
     },
     {
       "pattern": "^https://team-ddev.1password.com"
+    },
+    {
+      "pattern": "^https://.*.archive.org"
     }
+
   ],
   "httpHeaders": [
     {
diff --git a/pkg/ddevapp/ddevapp.go b/pkg/ddevapp/ddevapp.go
index 3ff2ff5fa..9dbd0d3d7 100644
--- a/pkg/ddevapp/ddevapp.go
+++ b/pkg/ddevapp/ddevapp.go
@@ -1187,28 +1187,13 @@ func (app *DdevApp) GetLocalTimezone() (string, error) {
 		timezone = os.Getenv("TZ")
 	} else {
 		localtimeFile := filepath.Join("/etc", "localtime")
-		timezoneFile, err := filepath.EvalSymlinks(localtimeFile)
+		var err error
+		timezone, err = filepath.EvalSymlinks(localtimeFile)
 		if err != nil {
 			return "", fmt.Errorf("unable to read timezone from %s file: %v", localtimeFile, err)
 		}
-		// /etc/localtime is a symlink to a file, for example:
-		// /usr/share/zoneinfo/Europe/London on Linux and WSL2
-		// /var/db/timezone/zoneinfo/Europe/London on macOS (the exact path to /zoneinfo/ may differ)
-		// We can search for anything after /zoneinfo/ in the file path
-		parts := strings.Split(strings.TrimSpace(timezoneFile), "/zoneinfo/")
-		if len(parts) != 2 {
-			return "", fmt.Errorf("unable to read timezone from %s file", timezoneFile)
-		}
-		timezone = parts[1]
-		if timezone == "" {
-			return "", fmt.Errorf("unable to read timezone from %s file", timezoneFile)
-		}
-	}
-	_, err := time.LoadLocation(timezone)
-	if err != nil {
-		return "", fmt.Errorf("failed to load timezone '%s': %v", timezone, err)
 	}
-	return timezone, nil
+	return util.GetTimezone(timezone)
 }
 
 // Start initiates docker-compose up
diff --git a/pkg/ddevapp/dotddev_assets/providers/README.txt b/pkg/ddevapp/dotddev_assets/providers/README.txt
index 7455b88de..6f48baf19 100644
--- a/pkg/ddevapp/dotddev_assets/providers/README.txt
+++ b/pkg/ddevapp/dotddev_assets/providers/README.txt
@@ -5,30 +5,53 @@ Providers README
 
 ## Introduction to Hosting Provider Integration
 
-DDEV's hosting provider integration lets you integrate with any upstream source of database dumps and files (such as your production or staging server) and provides examples of configuration for Acquia, Platform.sh, Pantheon, rsync, etc.
+DDEV offers hosting provider integration and sample integrations for Pantheon, Platform.sh and Acquia hosting, along with other examples.
 
-The best part of this is you can change them and adapt them in any way you need to, they're all short scripted recipes. There are several example recipes created in the .ddev/providers directory of every project or see them in the code at https://github.com/ddev/ddev/tree/master/pkg/ddevapp/dotddev_assets/providers.
+Hosting provider integration allows connecting with your upstream hosting. `ddev pull <provider>` downloads and `ddev push <provider>` uploads the **database** and the **user-generated files** to an upstream provider. It does *not* push (deploy) or pull your code. Your code should be under version control in for example Git.
 
-ddev provides the `pull` command with whatever recipes you have configured. For example, `ddev pull acquia` if you have created `.ddev/providers/acquia.yaml`.
+DDEV provides ready-to-go integrations for Platform.sh, Acquia, and Lagoon in every project, see the .ddev/providers directory. These can be used as is, or they can be modified as you see fit (but remove the `#ddev-generated` line so DDEV doesn't replace them with the defaults).
 
-ddev also provides the `push` command to push database and files to upstream. This is very dangerous to your upstream site and should only be used with extreme caution. It's recommended not even to implement the push stanzas in your yaml file, but if it fits your workflow, use it well.
+In addition, each project includes example recipes https://github.com/ddev/ddev/tree/master/pkg/ddevapp/dotddev_assets/providers for Pantheon, Git, local files, and `rsync` in its `.ddev/providers` directory, which you can use and adapt however you’d like.
 
-Each provider recipe is a yaml file that can be named any way you want to name it. The examples are mostly named after the hosting providers, but they could be named "upstream.yaml" or "live.yaml", so you could `ddev pull upstream` or `ddev pull live`. If you wanted different upstream environments to pull from, you could name one "prod" and one "dev" and `ddev pull prod` and `ddev pull dev`.
+DDEV provides the `pull` command with whatever recipes you have configured. For example, `ddev pull platform` is available by default, and `ddev pull pantheon` is available if you have created `.ddev/providers/pantheon.yaml`.
 
-Several example recipes are at https://github.com/ddev/ddev/tree/master/pkg/ddevapp/dotddev_assets/providers and in this directory.
+DDEV also provides the `push` command to push database and files to upstream. This is very dangerous to your upstream site and should only be used when appropriate. We don’t even recommended implementing the push stanzas in your YAML file, but it’s there if it suits your workflow.
+
+Each provider recipe is a YAML file that can have whatever name you want. The examples are mostly named after the hosting providers, but they could be named `upstream.yaml` or `live.yaml`, so you could `ddev pull upstream` or `ddev pull live`. If you wanted different upstream environments to pull from, you could name one “prod” and one “dev” and `ddev pull prod` and `ddev pull dev`.
+
+Recipes are provided for:
+- Acquia .ddev/providers/acquia.yaml
+- Git .ddev/providers/git.yaml.example
+- Lagoon .ddev/providers/lagoon.yaml
+- Local files .ddev/providers/localfile.yaml.example (like Dropbox, for example)
+- Pantheon .ddev/providers/pantheon.yaml.example
+- Platform.sh .ddev/providers/platform.yaml
+- rsync .ddev/providers/rsync.yaml.example
+- Upsun .ddev/providers/upsun.yaml
+
+Recipes are provided for Acquia (see .ddev/providers/acquia.yaml), Local files (see .ddev/providers/localfile.yaml.example) (like Dropbox, for example), Pantheon (see .ddev/providers/pantheon.yaml.example), Platform.sh (see .ddev/providers/platform.yaml, and rsync (see .ddev/providers/rsync.yaml.example).
 
 Each provider recipe is a file named `<provider>.yaml` and consists of several mostly-optional stanzas:
 
-* `environment_variables`: Environment variables will be created in the web container for each of these during pull or push operations. They're used to provide context (project id, environment name, etc.) for each of the other stanzas.
-* `db_pull_command`: A script that determines how ddev should pull a database. It's job is to create a gzipped database dump in /var/www/html/.ddev/.downloads/db.sql.gz.
-* `files_pull_command`: A script that determines how ddev can get user-generated files from upstream. Its job is to copy the files from upstream to  /var/www/html/.ddev/.downloads/files.
-* `db_push_command`: A script that determines how ddev should push a database. It's job is to take a  gzipped database dump from /var/www/html/.ddev/.downloads/db.sql.gz and load it on the hosting provider.
-* `files_pull_command`: A script that determines how ddev push user-generated files to upstream. Its job is to copy the files from the project's user-files directories ($DDEV_FILES_DIRS) to the correct places on the upstream provider.
+- `environment_variables`: Environment variables will be created in the web container for each of these during pull or push operations. They’re used to provide context (project ID, environment name, etc.) for each of the other stanzas. This stanza is not used in more recent hosting integrations, since providing the environment variables in `config.yaml` or via `ddev pull xxx --environment=VARIABLE=value` is preferred.
+- `db_pull_command`: A script that determines how DDEV should obtain a database. Its job is to create a gzipped database dump in `/var/www/html/.ddev/.downloads/db.sql.gz`. This is optional; if nothing has to be done to obtain the database dump, this step can be omitted.
+- `db_import_command`: (optional) A script that imports the downloaded database. This is for advanced usages like multiple databases. The default behavior only imports a single database into the `db` database. The [localfile example](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/localfile.yaml.example) uses this technique.
+- `files_pull_command`: A script that determines how DDEV can get user-generated files from upstream. Its job is to copy the files from upstream to `/var/www/html/.ddev/.downloads/files`. If nothing has to be done to obtain the files, this step can run `true`.
+- `files_import_command`: (optional) A script that imports the downloaded files. There are a number of situations where it’s messy to push a directory of files around, and one can put it directly where it’s needed. The [localfile example](https://github.com/ddev/ddev/blob/master/pkg/ddevapp/dotddev_assets/providers/localfile.yaml.example) uses this technique.
+- `db_push_command`: A script that determines how DDEV should push a database. Its job is to take a gzipped database dump from `/var/www/html/.ddev/.downloads/db.sql.gz` and load it on the hosting provider.
+- `files_push_command`: A script that determines how DDEV push user-generated files to upstream. Its job is to copy the files from the project’s user-files directories (`$DDEV_FILES_DIRS`) to the correct places on the upstream provider.
 
 The environment variables provided to custom commands (see https://ddev.readthedocs.io/en/stable/users/extend/custom-commands/#environment-variables-provided) are also available for use in these recipes.
 
+There are hooks (see https://ddev.readthedocs.io/en/stable/users/configuration/hooks/) available to execute commands before and after each pull or push: `pre-pull`, `post-pull`, `pre-push`, `post-push`. These could be for example a `ddev snapshot` to backup the database before a pull or a specific task to clear/warm-up caches of your application.
+
+## Example Integrations and Hints
+
+- All of the [supplied integrations](https://github.com/ddev/ddev/tree/master/pkg/ddevapp/dotddev_assets/providers) are examples of what you can do.
+- You can name a provider anything you want. For example, an Acquia integration doesn’t have to be named “acquia”, it can be named “upstream”. This is a great technique for downloading a particular multisite (see https://stackoverflow.com/a/68553116/215713).
+
 ### Provider Debugging
 
-You can uncomment the `set -x` in each stanza to see more of what's going on. It really helps.
+You can uncomment the `set -x` in each stanza to see more of what’s going on. It really helps. Watch it as you do a `ddev pull <whatever>`.
 
-Although the various commands could be executed on the host or in other containers if configured that way, most commands are executed in the web container. So the best thing to do is to `ddev ssh` and manually execute each command you want to use. When you have it right, use it in the yaml file.
+Although the various commands could be executed on the host or in other containers if configured that way, most commands are executed in the web container. So the best thing to do is to `ddev ssh` and manually execute each command you want to use. When you have it right, use it in the YAML file.
diff --git a/pkg/ddevapp/dotddev_assets/providers/acquia.yaml b/pkg/ddevapp/dotddev_assets/providers/acquia.yaml
index b3d940abe..f3028e5f0 100755
--- a/pkg/ddevapp/dotddev_assets/providers/acquia.yaml
+++ b/pkg/ddevapp/dotddev_assets/providers/acquia.yaml
@@ -6,20 +6,25 @@
 # 1. Get your Acquia API token from your Account Settings->API Tokens.
 # 2. Make sure your ssh key is authorized on your Acquia account at Account Settings->SSH Keys
 # 3. `ddev auth ssh` (this typically needs only be done once per ddev session, not every pull).
-# 4. Add / update the web_environment section in ~/.ddev/global_config.yaml
-#    or your project config.yamlwith the API keys:
+# 4. Add / update the web_environment section in ~/.ddev/global_config.yaml with the API keys:
 #    ```yaml
 #    web_environment:
-#    - ACQUIA_API_KEY=xxxxxxxx
-#    - ACQUIA_API_SECRET=xxxxx
+#        - ACQUIA_API_KEY=xxxxxxxx
+#        - ACQUIA_API_SECRET=xxxxx
 #    ```
-# 5. Add the ACQUIA_ENVIRONMENT_ID environment variable to your project config.yaml, for example:
+#    You can also do this with `ddev config global --web-environment-add="ACQUIA_API_KEY=xxxxxxxx,ACQUIA_API_SECRET=xxxxx"`.
+#
+# 5. Add the ACQUIA_ENVIRONMENT_ID environment variable to your project `.ddev/config.yaml`, for example:
 #    ```yaml
 #    web_environment:
-#    - ACQUIA_ENVIRONMENT_ID=project1.dev
-#   - On the Acquia Cloud Platform you can find this out by navigating to the environments page,
-#     clicking on the header and look for the "SSH URL" line.
-#     Eg. `project1.dev@cool-projects.acquia-sites.com` would have a project ID of `project1.dev`
+#        - ACQUIA_ENVIRONMENT_ID=project1.dev
+#    ```
+#    You can also do this with `ddev config --web-environment-add="ACQUIA_ENVIRONMENT_ID=project1.dev"`.
+#
+#    On the Acquia Cloud Platform you can find this out by navigating to the environments page,
+#    clicking on the header and look for the "SSH URL" line.
+#    Eg. `project1.dev@cool-projects.acquia-sites.com` would have a project ID of `project1.dev`
+#
 # 6. `ddev restart`
 # 7. Use `ddev pull acquia` to pull the project database and files.
 # 8. Optionally use `ddev push acquia` to push local files and database to Acquia. Note that `ddev push` is a command that can potentially damage your production site, so this is not recommended.
@@ -31,11 +36,11 @@
 
 auth_command:
   command: |
-     set -eu -o pipefail
-     if [ -z "${ACQUIA_API_KEY:-}" ] || [ -z "${ACQUIA_API_SECRET:-}" ]; then echo "Please make sure you have set ACQUIA_API_KEY and ACQUIA_API_SECRET in ~/.ddev/global_config.yaml" && exit 1; fi
-      if [ -z "${ACQUIA_ENVIRONMENT_ID:-}" ] ; then echo "Please set ACQUIA_ENVIRONMENT_ID via config.yaml or with '--environment=ACQUIA_ENVIRONMENT_ID=xxx'" && exit 1; fi
-      ssh-add -l >/dev/null || ( echo "Please 'ddev auth ssh' before running this command." && exit 1 )
-      acli -n auth:login -n --key="${ACQUIA_API_KEY}" --secret="${ACQUIA_API_SECRET}"
+    set -eu -o pipefail
+    if [ -z "${ACQUIA_API_KEY:-}" ] || [ -z "${ACQUIA_API_SECRET:-}" ]; then echo "Please make sure you have set ACQUIA_API_KEY and ACQUIA_API_SECRET in ~/.ddev/global_config.yaml" && exit 1; fi
+    if [ -z "${ACQUIA_ENVIRONMENT_ID:-}" ] ; then echo "Please set ACQUIA_ENVIRONMENT_ID via config.yaml or with '--environment=ACQUIA_ENVIRONMENT_ID=xxx'" && exit 1; fi
+    ssh-add -l >/dev/null || ( echo "Please 'ddev auth ssh' before running this command." && exit 1 )
+    acli -n auth:login -n --key="${ACQUIA_API_KEY}" --secret="${ACQUIA_API_SECRET}"
 
 db_pull_command:
   command: |
diff --git a/pkg/ddevapp/dotddev_assets/providers/lagoon.yaml b/pkg/ddevapp/dotddev_assets/providers/lagoon.yaml
index 78cbf6e50..5e50f15f5 100755
--- a/pkg/ddevapp/dotddev_assets/providers/lagoon.yaml
+++ b/pkg/ddevapp/dotddev_assets/providers/lagoon.yaml
@@ -7,6 +7,13 @@
 # 2. Configure an SSH key for your Lagoon user https://docs.lagoon.sh/using-lagoon-advanced/ssh/
 # 3. `ddev auth ssh`.
 # 4. Add LAGOON_PROJECT and LAGOON_ENVIRONMENT variables to your project in 'web_environment' or a '.ddev/.env'
+#    ```yaml
+#    web_environment:
+#        - LAGOON_PROJECT=<project-name>
+#        - LAGOON_ENVIRONMENT=<environment-name>
+#    ```
+#    You can also do this with `ddev config --web-environment-add="LAGOON_PROJECT=<project-name>,LAGOON_ENVIRONMENT=<environment-name>"`.
+#
 # 5. `ddev restart`
 #
 # 'ddev pull lagoon'
@@ -46,4 +53,3 @@ files_push_command:
     set -eu -o pipefail
     #set -x   # You can enable bash debugging output by uncommenting
     lagoon-sync sync files -p ${LAGOON_PROJECT} -e local -t ${LAGOON_ENVIRONMENT} --no-interaction 
-
diff --git a/pkg/ddevapp/dotddev_assets/providers/pantheon.yaml.example b/pkg/ddevapp/dotddev_assets/providers/pantheon.yaml.example
index e6e6fb8b8..c450f8a78 100644
--- a/pkg/ddevapp/dotddev_assets/providers/pantheon.yaml.example
+++ b/pkg/ddevapp/dotddev_assets/providers/pantheon.yaml.example
@@ -9,10 +9,11 @@
 #    a. Login to your Pantheon Dashboard, and [Generate a Machine Token](https://pantheon.io/docs/machine-tokens/) for ddev to use.
 #    b. Add the API token to the `web_environment` section in your global ddev configuration at ~/.ddev/global_config.yaml
 #
-#    ```
+#    ```yaml
 #    web_environment:
-#    - TERMINUS_MACHINE_TOKEN=abcdeyourtoken
+#        - TERMINUS_MACHINE_TOKEN=abcdeyourtoken
 #    ```
+#    You can also do this with `ddev config global --web-environment-add="TERMINUS_MACHINE_TOKEN=abcdeyourtoken"`.
 #
 # 2. Choose a Pantheon site and environment you want to use with ddev. You can usually use the site name, but in some environments you may need the site uuid, which is the long 3rd component of your site dashboard URL. So if the site dashboard is at <https://dashboard.pantheon.io/sites/009a2cda-2c22-4eee-8f9d-96f017321555#dev/>, the site ID is 009a2cda-2c22-4eee-8f9d-96f017321555.
 #
diff --git a/pkg/ddevapp/dotddev_assets/providers/platform.yaml b/pkg/ddevapp/dotddev_assets/providers/platform.yaml
index 36b37bd14..955d8bd62 100644
--- a/pkg/ddevapp/dotddev_assets/providers/platform.yaml
+++ b/pkg/ddevapp/dotddev_assets/providers/platform.yaml
@@ -14,14 +14,19 @@
 #    b. Add the API token to the `web_environment` section in your global ddev configuration at ~/.ddev/global_config.yaml:
 #    ```yaml
 #    web_environment:
-#    - PLATFORMSH_CLI_TOKEN=abcdeyourtoken
+#        - PLATFORMSH_CLI_TOKEN=abcdeyourtoken
 #    ```
+#    You can also do this with `ddev config global --web-environment-add="PLATFORMSH_CLI_TOKEN=abcdeyourtoken"`.
+#
 # 3. Add PLATFORM_PROJECT and PLATFORM_ENVIRONMENT and optional PLATFORM_APP (only if your environment contains more than one app) variables to your project `.ddev/config.yaml` or a `.ddev/config.platform.yaml`
 #    ```yaml
 #    web_environment:
-#    - PLATFORM_PROJECT=nf4amudfn23biyourproject
-#    - PLATFORM_ENVIRONMENT=main
-#    - PLATFORM_APP=app
+#        - PLATFORM_PROJECT=nf4amudfn23biyourproject
+#        - PLATFORM_ENVIRONMENT=main
+#        - PLATFORM_APP=app
+#    ```
+#    You can also do this with `ddev config --web-environment-add="PLATFORM_PROJECT=nf4amudfn23biyourproject,PLATFORM_ENVIRONMENT=main,PLATFORM_APP=app"`.
+#
 # 4. `ddev restart`
 # 5. Run `ddev pull platform`. After you agree to the prompt, the current upstream database and files will be downloaded.
 # 6. Optionally use `ddev push platform` to push local files and database to platform.sh. Note that `ddev push` is a command that can potentially damage your production site, so this is not recommended.
diff --git a/pkg/ddevapp/dotddev_assets/providers/upsun.yaml b/pkg/ddevapp/dotddev_assets/providers/upsun.yaml
index 5770e7a84..1a4a42dc4 100644
--- a/pkg/ddevapp/dotddev_assets/providers/upsun.yaml
+++ b/pkg/ddevapp/dotddev_assets/providers/upsun.yaml
@@ -11,13 +11,18 @@
 #    b. Add the API token to the `web_environment` section in your global ddev configuration at ~/.ddev/global_config.yaml:
 #    ```yaml
 #    web_environment:
-#    - UPSUN_CLI_TOKEN=abcdeyourtoken
+#        - UPSUN_CLI_TOKEN=abcdeyourtoken
 #    ```
+#    You can also do this with `ddev config global --web-environment-add="UPSUN_CLI_TOKEN=abcdeyourtoken"`.
+#
 # 3. Add UPSUN_PROJECT and UPSUN_ENVIRONMENT variables to your project `.ddev/config.yaml` or a `.ddev/config.upsun.yaml`
 #    ```yaml
 #    web_environment:
-#    - UPSUN_PROJECT=nf4amudfn23biyourproject
-#    - UPSUN_ENVIRONMENT=main
+#        - UPSUN_PROJECT=nf4amudfn23biyourproject
+#        - UPSUN_ENVIRONMENT=main
+#    ```
+#    You can also do this with `ddev config --web-environment-add="UPSUN_PROJECT=nf4amudfn23biyourproject,UPSUN_ENVIRONMENT=main"`.
+#
 # 4. `ddev restart`
 # 5. Run `ddev pull upsun`. After you agree to the prompt, the current upstream database and files will be downloaded.
 # 6. Optionally use `ddev push upsun` to push local files and database to Upsun. Note that `ddev push` is a command that can potentially damage your production site, so this is not recommended.
diff --git a/pkg/ddevapp/schema.json b/pkg/ddevapp/schema.json
index 73d51bf4c..34cc56325 100644
--- a/pkg/ddevapp/schema.json
+++ b/pkg/ddevapp/schema.json
@@ -74,6 +74,85 @@
           "description": "Specify the database version to use.",
           "type": "string"
         }
+      },
+      "if": {
+        "properties": {
+          "type": {
+            "const": "mariadb"
+          }
+        }
+      },
+      "then": {
+        "properties": {
+          "version": {
+            "enum": [
+              "5.5",
+              "10.0",
+              "10.1",
+              "10.2",
+              "10.3",
+              "10.4",
+              "10.5",
+              "10.6",
+              "10.7",
+              "10.8",
+              "10.11",
+              "11.4"
+            ]
+          }
+        }
+      },
+      "else": {
+        "if": {
+          "properties": {
+            "type": {
+              "const": "mysql"
+            }
+          }
+        },
+        "then": {
+          "properties": {
+            "version": {
+              "enum": [
+                "5.5",
+                "5.6",
+                "5.7",
+                "8.0"
+              ]
+            }
+          }
+        },
+        "else": {
+          "if": {
+            "properties": {
+              "type": {
+                "const": "postgres"
+              }
+            }
+          },
+          "then": {
+            "properties": {
+              "version": {
+                "enum": [
+                  "9",
+                  "10",
+                  "11",
+                  "12",
+                  "13",
+                  "14",
+                  "15",
+                  "16",
+                  "17"
+                ]
+              }
+            }
+          },
+          "else": {
+            "not": {
+              "required": ["version"]
+            }
+          }
+        }
       }
     },
     "dbimage_extra_packages": {
diff --git a/pkg/ddevapp/templates.go b/pkg/ddevapp/templates.go
index 38e969906..cd03d1c84 100644
--- a/pkg/ddevapp/templates.go
+++ b/pkg/ddevapp/templates.go
@@ -194,8 +194,8 @@ const ConfigInstructions = `
 
 # You can inject environment variables into the web container with:
 # web_environment:
-# - SOMEENV=somevalue
-# - SOMEOTHERENV=someothervalue
+#     - SOMEENV=somevalue
+#     - SOMEOTHERENV=someothervalue
 
 # no_project_mount: false
 # (Experimental) If true, DDEV will not mount the project into the web container;
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-backdrop.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-backdrop.conf
index 647dc1631..1e462ac0b 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-backdrop.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-backdrop.conf
@@ -55,6 +55,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-craftcms.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-craftcms.conf
index cdae2a722..ef29c8871 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-craftcms.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-craftcms.conf
@@ -60,6 +60,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Prevent clients from accessing hidden files (starting with a dot)
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal.conf
index 464fa0f1f..9dec27215 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal.conf
@@ -54,6 +54,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal10.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal10.conf
index cbff2880e..91e6e90e6 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal10.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal10.conf
@@ -54,6 +54,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal6.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal6.conf
index b9ddfe968..36b5b5de2 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal6.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal6.conf
@@ -65,6 +65,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal7.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal7.conf
index 88edf0ebe..dd1b970e0 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal7.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal7.conf
@@ -58,6 +58,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal8.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal8.conf
index fd61da9b2..228696686 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal8.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal8.conf
@@ -53,6 +53,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal9.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal9.conf
index 379e91ec6..e2cb92ea7 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-drupal9.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-drupal9.conf
@@ -53,6 +53,12 @@ server {
         # fastcgi_read_timeout should match max_execution_time in php.ini
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
         fastcgi_param HTTPS $fcgi_https;
     }
 
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-laravel.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-laravel.conf
index c3154a439..5db973fb6 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-laravel.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-laravel.conf
@@ -49,6 +49,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-magento.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-magento.conf
index 2dc680f7b..024ee0271 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-magento.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-magento.conf
@@ -58,6 +58,12 @@ server {
         fastcgi_param HTTPS $fcgi_https;
         fastcgi_param MAGE_RUN_CODE $mage_run_code;
         fastcgi_param MAGE_RUN_TYPE $mage_run_type;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-magento2.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-magento2.conf
index da1622ae4..651138973 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-magento2.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-magento2.conf
@@ -49,6 +49,12 @@ server {
         fastcgi_param HTTPS $fcgi_https;
         fastcgi_param MAGE_RUN_CODE $mage_run_code;
         fastcgi_param MAGE_RUN_TYPE $mage_run_type;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-php.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-php.conf
index b56f9319c..d6edeeb76 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-php.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-php.conf
@@ -50,6 +50,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Prevent clients from accessing hidden files (starting with a dot)
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-shopware6.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-shopware6.conf
index 5709405be..6b8294f72 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-shopware6.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-shopware6.conf
@@ -66,6 +66,12 @@ server {
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
         http2_push_preload on;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-typo3.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-typo3.conf
index be29b5c84..24e50d7fd 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-typo3.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-typo3.conf
@@ -83,6 +83,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx-site-wordpress.conf b/pkg/ddevapp/webserver_config_assets/nginx-site-wordpress.conf
index 06f1309b2..ada1f614d 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx-site-wordpress.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx-site-wordpress.conf
@@ -76,6 +76,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/ddevapp/webserver_config_assets/nginx_second_docroot_example-site-php.conf b/pkg/ddevapp/webserver_config_assets/nginx_second_docroot_example-site-php.conf
index ffebb6b64..dde097aff 100644
--- a/pkg/ddevapp/webserver_config_assets/nginx_second_docroot_example-site-php.conf
+++ b/pkg/ddevapp/webserver_config_assets/nginx_second_docroot_example-site-php.conf
@@ -53,6 +53,12 @@ server {
         fastcgi_read_timeout 10m;
         fastcgi_param SERVER_NAME $host;
         fastcgi_param HTTPS $fcgi_https;
+        # Pass the X-Accel-* headers to facilitate testing.
+        fastcgi_pass_header "X-Accel-Buffering";
+        fastcgi_pass_header "X-Accel-Charset";
+        fastcgi_pass_header "X-Accel-Expires";
+        fastcgi_pass_header "X-Accel-Limit-Rate";
+        fastcgi_pass_header "X-Accel-Redirect";
     }
 
     # Expire rules for static content
diff --git a/pkg/globalconfig/global_config.go b/pkg/globalconfig/global_config.go
index f3c595a5a..df7300776 100644
--- a/pkg/globalconfig/global_config.go
+++ b/pkg/globalconfig/global_config.go
@@ -368,8 +368,8 @@ func WriteGlobalConfig(config GlobalConfig) error {
 #
 # You can inject environment variables into the web container with:
 # web_environment:
-# - SOMEENV=somevalue
-# - SOMEOTHERENV=someothervalue
+#     - SOMEENV=somevalue
+#     - SOMEOTHERENV=someothervalue
 
 # Adjust the default table style used in ddev list and describe
 # table_style: default
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 19deba4e7..42797481d 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -9,6 +9,7 @@ import (
 	osexec "os/exec"
 	"os/user"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"strings"
 	"time"
@@ -388,3 +389,33 @@ func Chmod(path string, mode os.FileMode) error {
 	}
 	return os.Chmod(path, mode)
 }
+
+// GetTimezone tries to find local timezone from the path, that can be
+// either $TZ environment variable or /etc/localtime symlink
+func GetTimezone(path string) (string, error) {
+	// Use case-insensitive search for /zoneinfo/ in the file path.
+	regex := regexp.MustCompile(`(?i)/.*?zoneinfo.*?/`)
+	parts := regex.Split(strings.TrimSpace(path), 2)
+	if len(parts) != 2 {
+		// If this is not a path, but timezone, return it.
+		_, err := time.LoadLocation(path)
+		if err == nil {
+			return path, nil
+		}
+		return "", fmt.Errorf("unable to read timezone from %s", path)
+	}
+	timezone := parts[1]
+	// Remove leading prefixes if they exist.
+	// https://stackoverflow.com/a/67888343/8097891
+	for _, prefix := range []string{"posix/", "right/"} {
+		timezone = strings.TrimPrefix(timezone, prefix)
+	}
+	if timezone == "" {
+		return "", fmt.Errorf("unable to read timezone from %s", path)
+	}
+	_, err := time.LoadLocation(timezone)
+	if err != nil {
+		return "", fmt.Errorf("failed to load timezone '%s': %v", timezone, err)
+	}
+	return timezone, nil
+}


Test patch:
diff --git a/docs/content/developers/buildkite-testmachine-setup.md b/docs/content/developers/buildkite-testmachine-setup.md
index 471be36a7..55a60023a 100644
--- a/docs/content/developers/buildkite-testmachine-setup.md
+++ b/docs/content/developers/buildkite-testmachine-setup.md
@@ -60,24 +60,16 @@ We are using [Buildkite](https://buildkite.com/ddev) for Windows and macOS testi
 13. `sudo systemctl enable buildkite-agent && sudo systemctl start buildkite-agent`
 14. In PowerShell: `wsl.exe --update`. Watch for the escalation to complete, it may require escalation.
 15. Open WSL2 and check out [ddev/ddev](https://github.com/ddev/ddev).
-16. Install Homebrew: `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`
-17. Configure brew in PATH with:
-
-     ```
-     echo 'export PATH="/snap/bin:/home/linuxbrew/.linuxbrew/bin:$PATH"' >>~/.bashrc
-     source ~/.bashrc
-     ```
-
-18. As root user (`sudo -s`), add sudo capability with `echo "ALL ALL=NOPASSWD: ALL" >/etc/sudoers.d/all && chmod 440 /etc/sudoers.d/all`.
-19. `git config --global --add safe.directory '*'`
-20. `echo "capath=/etc/ssl/certs/" >>~/.curlrc`
-21. `nc.exe -L -p 9003` on Windows to trigger and allow Windows Defender.
-22. Run `ngrok authtoken <token>` with token for free account.
-23. Install [winaero tweaker](https://winaero.com/request.php?1796) and “Enable user autologin checkbox”. Set up the machine to [automatically log in on boot](https://www.cnet.com/how-to/automatically-log-in-to-your-windows-10-pc/).  Then run netplwiz, provide the password for the main user, uncheck “require a password to log in”.
-24. In “Advanced Windows Update Settings” enable “Receive updates for other Microsoft products” to make sure you get WSL2 kernel upgrades. Make sure to run Windows Update to get the latest kernel.
-25. Turn off the `System` -> `Notifications` -> `Additional settings` that cause the "Windows experience" prompts after upgrades:
+16. As root user (`sudo -s`), add sudo capability with `echo "ALL ALL=NOPASSWD: ALL" >/etc/sudoers.d/all && chmod 440 /etc/sudoers.d/all`.
+17. `git config --global --add safe.directory '*'`
+18. `echo "capath=/etc/ssl/certs/" >>~/.curlrc`
+19. `nc.exe -L -p 9003` on Windows to trigger and allow Windows Defender.
+20. Run `ngrok authtoken <token>` with token for free account.
+21. Install [winaero tweaker](https://winaero.com/request.php?1796) and “Enable user autologin checkbox”. Set up the machine to [automatically log in on boot](https://www.cnet.com/how-to/automatically-log-in-to-your-windows-10-pc/).  Then run netplwiz, provide the password for the main user, uncheck “require a password to log in”.
+22. In “Advanced Windows Update Settings” enable “Receive updates for other Microsoft products” to make sure you get WSL2 kernel upgrades. Make sure to run Windows Update to get the latest kernel.
+23. Turn off the `System` -> `Notifications` -> `Additional settings` that cause the "Windows experience" prompts after upgrades:
     ![disable_windows_experience](../images/disable_windows_experience.png)
-26. Edit the `~/.wslconfig` on Windows to add appropriate WSL2 memory allocation and `autoMemoryReclaim`
+24. Edit the `~/.wslconfig` on Windows to add appropriate WSL2 memory allocation and `autoMemoryReclaim`
 
     ```
     memory=12GB
diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go
index 041a28851..8139b6258 100644
--- a/pkg/util/utils_test.go
+++ b/pkg/util/utils_test.go
@@ -11,6 +11,7 @@ import (
 	"github.com/ddev/ddev/pkg/output"
 	"github.com/ddev/ddev/pkg/util"
 	asrt "github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 // TestRandString ensures that RandString only generates string of the correct value and characters.
@@ -194,3 +195,38 @@ func TestArrayToReadableOutput(t *testing.T) {
 	_, err := util.ArrayToReadableOutput([]string{})
 	assert.EqualErrorf(err, "empty slice", "Expected error when passing an empty slice")
 }
+
+// TestGetTimezone tests GetTimezone
+func TestGetTimezone(t *testing.T) {
+	testCases := []struct {
+		description string
+		input       string
+		result      string
+		error       string
+	}{
+		{"$TZ env var", "Europe/London", "Europe/London", ""},
+		{"Linux /etc/localtime symlink", "/usr/share/zoneinfo/Europe/London", "Europe/London", ""},
+		{"Linux /etc/localtime posix symlink", "/usr/share/zoneinfo/posix/Europe/London", "Europe/London", ""},
+		{"Linux /etc/localtime right symlink", "/usr/share/zoneinfo/right/Europe/London", "Europe/London", ""},
+		{"/etc/localtime is not a symlink", "/etc/localtime", "", "unable to read timezone from /etc/localtime"},
+		{"macOS /etc/localtime symlink", "/var/db/timezone/zoneinfo/Europe/London", "Europe/London", ""},
+		{"macOS Sonoma /etc/localtime symlink", "/private/var/db/timezone/tz/2024a.1.0/zoneinfo/Europe/London", "Europe/London", ""},
+		{"macOS Sequoia /etc/localtime symlink", "/usr/share/zoneinfo.default/Europe/London", "Europe/London", ""},
+		{"Case-insensitive search for /zoneinfo/ in the path", "/path/to/TestZoneInfoTest/Europe/London", "Europe/London", ""},
+		{"Timezone has wrong format", "/Europe/London", "", "unable to read timezone from /Europe/London"},
+		{"Not real timezone", "Europe/Test", "", "unable to read timezone from Europe/Test"},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.description, func(t *testing.T) {
+			timezone, err := util.GetTimezone(tc.input)
+			require.Equal(t, tc.result, timezone)
+			if tc.error == "" {
+				require.NoError(t, err)
+			} else {
+				require.Error(t, err)
+				require.Contains(t, err.Error(), tc.error)
+			}
+		})
+	}
+}