Serving Sites from the Web Subdirectory

Learn how to create a nested docroot to serve your Pantheon site from.

Contributors: Andrew Taylor


The docroot is the directory from which your site is served. On Pantheon, this defaults to the root directory of the site's codebase (code). Specifying web_docroot: true in your pantheon.yml file or in the pantheon.upstream.yml file in your upstream allows you to serve site files from the web subdirectory of your site's code repository on all Pantheon environments (e.g. code/web).

Advantages and Use Cases

While URLs are limited to the web docroot, PHP is not. Using a nested docroot allows you to put PHP files for use in your web application one level above the web docroot so they are accessible via PHP but not from the web.

This is especially useful for third party dependencies, such as those installed and managed via Composer.

Disable One-click Updates

If you wish to stop using One-click Dashboard updates on a particular site, and instead intend to update your site with Composer, switch the site's upstream to an empty repository using Terminus:

terminus site:upstream:set <site> empty-7
terminus site:upstream:set <site> empty
terminus site:upstream:set <site> empty-wordpress

Enable Nested Docroot

Enable nested docroot by adjusting your site's pantheon.yml file. Below we recommend using Git, but you can also use SFTP to set up your site.

  1. Set the Dev environment's connection mode to Git from within the Site Dashboard or via Terminus:

    $ terminus connection:set <site>.<env> git
    
  2. Clone the site's codebase, if you haven't already.

  3. Create a pantheon.yml file if it doesn't already exist.
  4. Add the line web_docroot: true to the top level of the YAML file, typically after api_version. For example:

    api_version: 1
    
    web_docroot: true
    
  5. Add, commit, and push the pantheon.yml file with Git.

  6. Follow the instructions in either Create a New Site with a Nested Docroot or Convert an Existing Site to Use a Nested Docroot below.

Create a New Site

If your site utilizes a Custom Upstream with a pantheon.upstream.yml file that enables nested docroot and the CMS code is in a web subdirectory, you are good to go! Otherwise, create a new site and follow the steps below.

Convert an Existing Site

You'll need to move the CMS code into the web subdirectory, either manually or by using one of the commands below.

Clone the site's codebase, then execute the following from the project root directory:

mkdir web
git mv -k $(find . -type f -maxdepth 1 | grep -v pantheon.yml) includes/ misc/ modules/ profiles/ scripts/ sites/ themes/ index.php web

These commands create the web subdirectory, then use Git to move required files into the nested docroot.

Your directory structure should look like this afterwards:

├── web
  ├── includes
  ├── index.php
  ├── misc
  ├── modules
  ├── profiles
  ├── scripts
  ├── sites
      └── all
          ├── modules
          └── themes
          └── default
          └── settings.php
  └── themes

Clone the site's codebase, then execute the following from the project root directory:

mkdir web
git mv -k $(find . -type f -maxdepth 1 | grep -v pantheon.yml) core drush modules profiles sites themes vendor index.php web

These commands create the web subdirectory, then use Git to move required files into the nested docroot.

Your directory structure should look like this afterwards:

├── web
  ├── core
  ├── drush
  ├── modules
  ├── profiles
  ├── sites
      ├── default
          ├── settings.php
  ├── themes
  ├── vendor
  ├── index.php

Clone the site's codebase, then execute the following from the project root directory:

mkdir web
git mv -k $(find . -type f -maxdepth 1  | grep -v pantheon.yml) wp-includes wp-content wp-admin ./*.php web

These commands create the web subdirectory, then use Git to move required files into the nested docroot.

Your directory structure should like like this afterwards:

├── web
  ├── index.php
  ├── wp-activate.php
  ├── wp-config.php
  ├── wp-comments-post.php
  ├── wp-blog-header.php
  ├── wp-admin
  ├── wp-cron.php
  ├── wp-load.php
  ├── wp-links-opml.php
  ├── wp-includes
  ├── xmlrpc.php
  ├── wp-trackback.php
  ├── wp-signup.php
  ├── wp-settings.php
  ├── wp-mail.php
  ├── wp-login.php
  ├── wp-content
    ├── index.php
    ├── mu-plugins
    ├── themes
    ├── plugins

The idea here is that find . -type f -maxdepth 1 finds all files at the document root, including the "dot" files, but skips all of the directories. We list the directories in Drupal/WordPress core out specifically, so that any user-defined directories stay behind. This may or may not produce the correct results, depending on what files you or your team has added. Please verify file relocation with git status after using one of these commands before committing and pushing.

Troubleshooting

Quicksilver Script Location

If you are using a Quicksilver platform hook with the type webphp, make sure that the path to the script is relative to the web docroot and not the project root.

For example, if your pantheon.yml has a script location definition of private/scripts/my_quicksilver_script.php, the file needs to be located at web/private/scripts/my_quicksilver_script.php. This is because webphp scripts are run with Nginx, which is serving from the nested docroot.

Can I specify a subdirectory other than web?

The directory name is not configurable, but you can create a symlink from some other directory to web.