github.com/drud/ddev@v1.21.5-alpha1.0.20230226034409-94fcc4b94453/docs/content/users/extend/customization-extendibility.md (about)

     1  # Extending and Customizing Environments
     2  
     3  DDEV provides several ways to customize and extend project environments.
     4  
     5  ## Changing PHP Version
     6  
     7  The project's `.ddev/config.yaml` file defines the PHP version to use. The [`php_version`](../configuration/config.md#php_version) can be changed to `5.6`, `7.0`, `7.1`, `7.2`,  `7.3`, `7.4`, `8.0`, `8.1`, or `8.2`. The current default is `8.0`.
     8  
     9  ### Older Versions of PHP
    10  
    11  [Support for older versions of PHP is available on ddev-contrib](https://github.com/drud/ddev-contrib/blob/master/docker-compose-services/old_php) via [custom docker-compose files](custom-compose-files.md).
    12  
    13  ## Changing Web Server Type
    14  
    15  DDEV supports nginx with php-fpm by default (`nginx-fpm`), and Apache with php-fpm (`apache-fpm`). You can change this with the [`webserver_type`](../configuration/config.md#webserver_type) config option, or using the [`ddev config`](../usage/commands.md#config) command with the `--webserver-type` flag.
    16  
    17  ## Adding Services to a Project
    18  
    19  DDEV provides everything you need to build a modern PHP application on your local machine. More complex web applications, however, often require integration with services beyond the usual requirements of a web and database server—maybe Apache Solr, Redis, Varnish, or many others. While DDEV likely won’t ever provide all of these additional services out of the box, it’s designed to provide simple ways to customize the environment and meet your project’s needs without reinventing the wheel.
    20  
    21  A collection of vetted service configurations is available in the [Additional Services Documentation](additional-services.md).
    22  
    23  If you need to create a service configuration for your project, see [Defining Additional Services with Docker Compose](custom-compose-files.md).
    24  
    25  ## Using Node.js with DDEV
    26  
    27  There are many ways to deploy Node.js in any project, so DDEV tries to let you set up any possibility you can come up with.
    28  
    29  * You can choose the Node.js version you want to use in `.ddev/config.yaml` with [`nodejs_version`](../configuration/config.md#nodejs_version).
    30  * [`ddev nvm`](../usage/commands.md#nvm) gives you the full capabilities of [Node Version Manager](https://github.com/nvm-sh/nvm).
    31  * [`ddev npm`](../usage/commands.md#npm) and [`ddev yarn`](../usage/commands.md#yarn) provide shortcuts to the `npm` and `yarn` commands inside the container, and their caches are persistent.
    32  * You can run Node.js daemons using [`web_extra_daemons`](#running-extra-daemons-in-the-web-container).
    33  * You can expose Node.js ports via `ddev-router` by using [`web_extra_exposed_ports`](#exposing-extra-ports-via-ddev-router).
    34  * You can manually run Node.js scripts using [`ddev exec <script>`](../usage/commands.md#exec) or `ddev exec nodejs <script>`.
    35  
    36  !!!tip "Please share your techniques!"
    37      There are several ways to share your favorite Node.js tips and techniques. Best are [ddev-get add-ons](additional-services.md#additional-service-configurations-and-add-ons-for-ddev), [Stack Overflow](https://stackoverflow.com/tags/ddev), and [ddev-contrib](https://github.com/drud/ddev-contrib).
    38  
    39  ## Running Extra Daemons in the Web Container
    40  
    41  There are several ways to run processes inside the `web` container.
    42  
    43  1. Manually execute them as needed, with [`ddev exec`](../usage/commands.md#exec), for example.
    44  2. Run them with a `post-start` [hook](../configuration/hooks.md).
    45  3. Run them automatically using `web_extra_daemons`.
    46  
    47  ### Running Extra Daemons with `post-start` Hook
    48  
    49  Daemons can be run with a `post-start` `exec` hook or automatically started using `supervisord`.
    50  
    51  A simple `post-start` exec hook in `.ddev/config.yaml` might look like:
    52  
    53  ```yaml
    54  hooks:
    55    post-start:
    56      - exec: "nohup php --docroot=/var/www/html/something -S 0.0.0.0:6666 &"
    57  ```
    58  
    59  ### Running Extra Daemons Using `web_extra_daemons`
    60  
    61  If you need extra daemons to start up automatically inside the web container, you can easily add them using [`web_extra_daemons`](../configuration/config.md#web_extra_daemons) in `.ddev/config.yaml`.
    62  
    63  You might be running Node.js daemons that serve a particular purpose, like `browsersync`, or more general daemons like a `cron` daemon.
    64  
    65  For example, you could use this configuration to run two instances of the Node.js HTTP server for different directories:
    66  
    67  ```yaml
    68  web_extra_daemons:
    69    - name: "http-1"
    70      command: "/var/www/html/node_modules/.bin/http-server -p 3000"
    71      directory: /var/www/html
    72    - name: "http-2"
    73      command: "/var/www/html/node_modules/.bin/http-server /var/www/html/sub -p 3000"
    74      directory: /var/www/html
    75  ```
    76  
    77  * `directory` should be the absolute path inside the container to the directory where the daemon should run.
    78  * `command` is best as a simple binary with its arguments, but Bash features like `cd` or `&&` work. If the program to be run is not in the `ddev-webserver` `$PATH` then it should have the absolute in-container path to the program to be run, like `/var/www/html/node_modules/.bin/http-server`.
    79  * `web_extra_daemons` is a shortcut for adding a configuration to `supervisord`, which organizes daemons inside the web container. If the default settings are inadequate for your use, you can write a [complete config file for your daemon](#explicit-supervisord-configuration-for-additional-daemons).
    80  * Your daemon is expected to run in the foreground, not to daemonize itself, `supervisord` will take care of that.
    81  * To see the results of the attempt to start your daemon, see [`ddev logs`](../usage/commands.md#logs) or `docker logs ddev-<project>-web`.
    82  
    83  ## Exposing Extra Ports via `ddev-router`
    84  
    85  If your `web` container has additional HTTP servers running inside it on different ports, those can be exposed using [`web_extra_exposed_ports`](../configuration/config.md#web_extra_exposed_ports) in `.ddev/config.yaml`. For example, this configuration would expose a `node-vite` HTTP server running on port 3000 inside the `web` container, via `ddev-router`, to ports 9998 (HTTP) and 9999 (HTTPS), so it could be accessed via `https://<project>.ddev.site:9999`:
    86  
    87  ```yaml
    88  web_extra_exposed_ports:
    89    - name: node-vite
    90      container_port: 3000
    91      http_port: 9998
    92      https_port: 9999
    93  ```
    94  
    95  The configuration below would expose a Node.js server running in the `web` container on port 3000 as `https://<project>.ddev.site:4000` and a “something” server running in the web container on port 4000 as `https://<project>.ddev.site:4000`:
    96  
    97  ```yaml
    98  web_extra_exposed_ports:
    99    - name: nodejs
   100      container_port: 3000
   101      http_port: 2999
   102      https_port: 3000
   103    - name: something
   104      container_port: 4000
   105      https_port: 4000
   106      http_port: 3999
   107  ```
   108  
   109  !!!warning "Fill in all three fields even if you don’t intend to use the `https_port`!"
   110      If you don’t add `https_port`, then it default to `0` and `ddev-router` will fail to start.
   111  
   112  ## Providing Custom Environment Variables to a Container
   113  
   114  You can set custom environment variables in several places:
   115  
   116  * The project’s [`web_environment`](../configuration/config.md#web_environment) setting in `.ddev/config.yaml` or `.ddev/config.*.yaml`:
   117  
   118      ```yaml
   119      web_environment:
   120      - MY_ENV_VAR=someval
   121      - MY_OTHER_ENV_VAR=someotherval
   122      ```
   123  
   124  * The global `web_environment` setting in `.ddev/global_config.yaml`.
   125  
   126  * An optional, project-level `.ddev/.env` file, which could look something like this:
   127  
   128      ```
   129      MY_ENV_VAR='someval'
   130      MY_OTHER_ENV_VAR='someotherval'
   131      ```
   132  
   133  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:
   134  
   135  ```sh
   136  # Set MY_ENV_VAR for the project
   137  ddev config --web-environment-add="MY_ENV_VAR=someval"
   138  
   139  # Set MY_ENV_VAR globally
   140  ddev config global --web-environment-add="MY_ENV_VAR=someval
   141  ```
   142  
   143  You can use the `--web-environment` flag to overwrite existing values rather than adding them.
   144  
   145  !!!warning "Don’t check in sensitive values!"
   146      Sensitive variables like API keys should not be checked in with your project. Typically you might use an `.env` file and _not_ check that in, but offer `.env.example` with expected keys that don’t have values. Some use global configuration for sensitive values, as that’s not normally checked in either.
   147  
   148  ### Altering the In-Container `$PATH`
   149  
   150  Sometimes it’s easiest to put the command you need into the existing `$PATH` using a symbolic link rather than changing the in-container `$PATH`. For example, the project `bin` directory is already included the `$PATH`. So if you have a command you want to run that’s not already in the `$PATH`, you can just add a symlink.
   151  
   152  Examples:
   153  
   154  * On Craft CMS, the `craft` script is often in the project root, which is not in the `$PATH`. But if you `mkdir bin && ln -s craft bin/craft` you should be able to use `ddev exec craft` just fine. (Note however that `ddev craft` takes care of this for you.)
   155  * On projects where the `vendor` directory is not in the project root (Acquia projects, for example, have `composer.json` and `vendor` in the `docroot` directory), you can `mkdir bin && ln -s docroot/vendor/bin/drush bin/drush` to put `drush` in your `$PATH`. (With projects like this, make sure to set `composer_root: docroot` so that `ddev composer` works properly.)
   156  
   157  You can also modify the `PATH` environment variable by adding a script to `<project>/.ddev/homeadditions/.bashrc.d/` or (global) `~/.ddev/homeadditions/.bashrc.d/`. For example, if your project vendor directory is not in the expected place (`/var/www/html/vendor/bin`) you can add a `<project>/.ddev/homeadditions/.bashrc.d/path.sh`:
   158  
   159  ```bash
   160  export PATH=$PATH:/var/www/html/somewhereelse/vendor/bin
   161  ```
   162  
   163  ## Custom nginx Configuration
   164  
   165  When you run [`ddev restart`](../usage/commands.md#restart) using `nginx-fpm`, DDEV creates a configuration customized to your project type in `.ddev/nginx_full/nginx-site.conf`. You can edit and override the configuration by removing the `#ddev-generated` line and doing whatever you need with it. After each change, run `ddev restart`. (For updates without restart, see [Troubleshooting nginx Configuration](#troubleshooting-nginx-configuration).)
   166  
   167  You can also have more than one config file in the `.ddev/nginx_full` directory, and each will be loaded when DDEV starts. This can be used for [serving multiple docroots](#multiple-docroots-in-nginx-advanced) and other techniques.
   168  
   169  ### Troubleshooting nginx Configuration
   170  
   171  * Any errors in your configuration may cause the `web` container to fail and try to restart. If you see that behavior, use [`ddev logs`](../usage/commands.md#logs) to diagnose.
   172  * The configuration is copied into the container during restart. Therefore it is not possible to simply edit the host file for the changes to take effect. You may want to edit the file directly inside the container at `/etc/nginx/sites-enabled/`. (For example, run [`ddev ssh`](../usage/commands.md#ssh) to get into the container.)
   173  * You can run `ddev exec nginx -t` to test whether your configuration inside the container is valid. (Or run [`ddev ssh`](../usage/commands.md#ssh) and run `nginx -t`.)
   174  * You can reload the nginx configuration by running either [`ddev restart`](../usage/commands.md#restart) or editing the configuration inside the container at `/etc/nginx/sites-enabled/` and running `ddev exec nginx -s reload` on the host system (inside the container just `nginx -s reload`).
   175  * The alias `Alias "/phpstatus" "/var/www/phpstatus.php"` is required for the health check script to work.
   176  
   177  ### Multiple Docroots in nginx (Advanced)
   178  
   179  It’s easiest to have different web servers in different DDEV projects, and DDEV projects can [easily communicate with each other](../usage/faq.md), but some sites require more than one docroot for a single project codebase. Sometimes this is because there’s an API built in the same codebase but using different code, or different code for different languages, etc.
   180  
   181  The generated `.ddev/nginx_full/seconddocroot.conf.example` demonstrates how to do this. You can create as many of these as you want: change the `servername` and the `root` and customize as needed.
   182  
   183  ### nginx Snippets
   184  
   185  To add an nginx snippet to the default config, add an nginx config file as `.ddev/nginx/<something>.conf`.
   186  
   187  For example, to make all HTTP URLs redirect to their HTTPS equivalents you might add `.ddev/nginx/redirect.conf` with this stanza:
   188  
   189  ```
   190      if ($http_x_forwarded_proto = "http") {
   191        return 301 https://$host$request_uri;
   192      }
   193  ```
   194  
   195  After adding a snippet, run `ddev restart` to make it take effect.
   196  
   197  ## Custom Apache Configuration
   198  
   199  If you’re using [`webserver_type: apache-fpm`](../configuration/config.md#webserver_type) in your `.ddev/config.yaml`, you can override the default site configuration by editing or replacing the DDEV-provided `.ddev/apache/apache-site.conf` configuration.
   200  
   201  * Edit the `.ddev/apache/apache-site.conf`.
   202  * Add your configuration changes.
   203  * Save your configuration file and run [`ddev restart`](../usage/commands.md#restart). If you encounter issues with your configuration or the project fails to start, use [`ddev logs`](../usage/commands.md#logs) to inspect the logs for possible Apache configuration errors.
   204  * Use `ddev exec apachectl -t` to do a general Apache syntax check.
   205  * The alias `Alias "/phpstatus" "/var/www/phpstatus.php"` is required for the health check script to work.
   206  * Any errors in your configuration may cause the `web` container to fail. If you see that behavior, use `ddev logs` to diagnose.
   207  
   208  !!!warning "Important!"
   209      Changes to `.ddev/apache/apache-site.conf` take place on a [`ddev restart`](../usage/commands.md#restart). You can also `ddev exec apachectl -k graceful` to reload the Apache configuration.
   210  
   211  ## Custom PHP Configuration (`php.ini`)
   212  
   213  You can provide additional PHP configuration for a project by creating a directory called `.ddev/php/` and adding any number of `*.ini` PHP configuration files.
   214  
   215  You should generally limit your override to any specific option(s) you need to customize. Every file in `.ddev/php/` will be copied into `/etc/php/[version]/(cli|fpm)/conf.d`, so it’s possible to replace files that already exist in the container. Common usage is to put custom overrides in a file called `my-php.ini`. Make sure you include the section header that goes with each item (like `[PHP]`).
   216  
   217  One interesting implication of this behavior is that it’s possible to disable extensions by replacing the configuration file that loads them. For instance, if you were to create an empty file at `.ddev/php/20-xdebug.ini`, it would replace the configuration that loads Xdebug, which would cause Xdebug to not be loaded!
   218  
   219  To load the new configuration, run [`ddev restart`](../usage/commands.md#restart).
   220  
   221  An example file in `.ddev/php/my-php.ini` might look like this:
   222  
   223  ```ini
   224  [PHP]
   225  max_execution_time = 240;
   226  ```
   227  
   228  ## Custom MySQL/MariaDB configuration (`my.cnf`)
   229  
   230  You can provide additional MySQL/MariaDB configuration for a project by creating a directory called `.ddev/mysql/` and adding any number of `*.cnf` MySQL configuration files. These files will be automatically included when MySQL is started. Make sure that the section header is included in the file.
   231  
   232  An example file in `.ddev/mysql/no_utf8mb4.cnf` might be:
   233  
   234  ```
   235  [mysqld]
   236  collation-server = utf8_general_ci
   237  character-set-server = utf8
   238  innodb_large_prefix=false
   239  ```
   240  
   241  To load the new configuration, run [`ddev restart`](../usage/commands.md#restart).
   242  
   243  ## Custom PostgreSQL Configuration
   244  
   245  If you’re using PostgreSQL, a default `posgresql.conf` is provided in `.ddev/postgres/postgresql.conf`. If you need to alter it, remove the `#ddev-generated` line and [`ddev restart`](../usage/commands.md#restart).
   246  
   247  ## Extending `config.yaml` with Custom `config.*.yaml` Files
   248  
   249  You may add additional `config.*.yaml` files to organize additional commands as you see fit for your project and team.
   250  
   251  For example, many teams commit their `config.yaml` and share it throughout the team, but some team members may require overrides to the checked-in version specifically for their environment and not checked in. For example, a team member may want to use a [`router_http_port`](../configuration/config.md#router_http_port) other than the team default due to a conflict in their development environment. In this case they could add `.ddev/config.ports.yaml`:
   252  
   253  ```yaml
   254  # My machine can’t use port 80 so override with port 8080, but don’t check this in!
   255  router_http_port: 8080
   256  ```
   257  
   258  `config.*.yaml` is by default omitted from Git by the `.ddev/.gitignore` file. You can commit it by using `git add -f .ddev/config.<something>.yaml`.
   259  
   260  Extra `config.*.yaml` files are loaded in lexicographic order, so `config.a.yaml` will be overridden by `config.b.yaml`.
   261  
   262  Teams may choose to use `config.local.yaml` or `config.override.yaml` for all local non-committed config changes, for example.
   263  
   264  `config.*.yaml` update configuration according to these rules:
   265  
   266  1. Simple fields like [`router_http_port`](../configuration/config.md#router_http_port) or [`webserver_type`](../configuration/config.md#webserver_type) are overwritten.
   267  2. Lists of strings like [`additional_hostnames`](../configuration/config.md#additional_hostnames) or [`additional_fqdns`](../configuration/config.md#additional_fqdns) are merged.
   268  3. The list of environment variables in [`web_environment`](../configuration/config.md#web_environment) are “smart merged”: if you add the same environment variable with a different value, the value in the override file will replace the value from `config.yaml`.
   269  4. Hook specifications in the [`hooks`](../configuration/config.md#hooks) variable are merged.
   270  
   271  If you need to _override_ existing values, set [`override_config: true`](../configuration/config.md#override_config) in the `config.*.yaml` where the override behavior should take place. Since `config.*.yaml` files are normally _merged_ into the configuration, some things can’t be overridden normally. For example, if you have [`nfs_mount_enabled: true`](../configuration/config.md#nfs_mount_enabled) you can’t override it with a merge and you can’t erase existing hooks or all environment variables. However, with `override_config: true` in a particular `config.*.yaml` file,
   272  
   273  ```yaml
   274  override_config: true
   275  nfs_mount_enabled: false
   276  ```
   277  
   278  can override the existing values, and
   279  
   280  ```yaml
   281  override_config: true
   282  hooks:
   283    post-start: []
   284  ```
   285  
   286  or
   287  
   288  ```yaml
   289  override_config: true
   290  additional_hostnames: []
   291  ```
   292  
   293  can have their intended affect.
   294  
   295  [`override_config`](../configuration/config.md#override_config) affects only behavior of the `config.*.yaml` file it exists in.
   296  
   297  To experiment with the behavior of a set of `config.*.yaml` files, use the [`ddev debug configyaml`](../usage/commands.md#debug-configyaml) file; it’s especially valuable with the `yq` command, for example `ddev debug configyaml | yq`.
   298  
   299  ## Explicit `supervisord` Configuration for Additional Daemons
   300  
   301  Although most extra daemons (like Node.js daemons, etc.) can be configured easily using [web_extra_daemons](#running-extra-daemons-in-the-web-container), there may be situations where you want complete control of the `supervisord` configuration.
   302  
   303  In these case you can create a `.ddev/web-build/<daemonname>.conf` with configuration like:
   304  
   305  ```
   306  [program:daemonname]
   307  command=/var/www/html/path/to/daemon
   308  directory=/var/www/html/
   309  autorestart=true
   310  startretries=10
   311  stdout_logfile=/proc/self/fd/2
   312  stdout_logfile_maxbytes=0
   313  redirect_stderr=true
   314  ```
   315  
   316  And create a `.ddev/web-build/Dockerfile.<daemonname>` to install the config file:
   317  
   318  ```dockerfile
   319  ADD .ddev/web-build/daemonname.conf /etc/supervisor/conf.d
   320  ```
   321  
   322  Full details for advanced configuration possibilities are in [Supervisor docs](http://supervisord.org/configuration.html#program-x-section-settings).