> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy WordPress Multisite on Upsun

> Complete the last required steps to successfully deploy a WordPress Multisite on Upsun.


export const GuidesRequirements = ({name}) => {
  const isSymfony = name === "Symfony";
  return <>
      <h2>Before you begin</h2>
      <p>You need:</p>
      <ul>
        <li>
          <a href="https://git-scm.com/downloads">Git</a>.{' '}
          Git is the primary tool to manage everything your app needs to run.
          Push commits to deploy changes and control configuration through YAML files.
          These files describe your infrastructure, making it transparent and version-controlled.
        </li>
        <li>
          An Upsun account.{' '}
          If you don't already have one, <a href="https://auth.upsun.com/register">register for a trial account</a>.{' '}
          You can sign up with an email address or an existing GitHub, Bitbucket, or Google account.
          If you choose one of these accounts, you can set a password for your Upsun account later.
        </li>
        <li>
          The {isSymfony ? <a href="https://symfony.com/download">Symfony CLI</a> : <a href="/cli">Upsun CLI</a>}.{' '}
          This lets you interact with your project from the command line.
          You can also do most things through the <a href="/docs/administration/web">Web Console</a>.
        </li>
      </ul>
    </>;
};

<Info>
  Before you start, check out the [Upsun demo app](https://console.upsun.com/projects/create-project)
  and the main [Getting started guide](/docs/get-started/here).
  These resources provide all the core concepts and common commands you need to know before using the following materials.
</Info>

You will need to make a few changes to your Upsun configuration for WordPress Multisite to successfully
deploy and operate.

Please note that these changes must only be made **after completing the
[Getting started guide](/docs/get-started/here)**. You should also already have a working WordPress site (see
**Assumptions** for the WordPress guides your WordPress site should be based on).

<GuidesRequirements name="WordPress" />

<Info>
  <h4>Assumptions</h4>
  There are many ways you can set up a
  [WordPress Multisite](https://developer.wordpress.org/advanced-administration/multisite/)
  or Upsun project. The instructions on this page are based on the following assumptions:

  * You selected **PHP** as your runtime, and **MariaDB** as a service during the Getting Started guide. It's also assumed
    that while using the Getting Started guide you named the project `myapp`, which you will notice is the top-level key in
    all configuration below.
  * Your database relationship name is `mariadb` (the default)
  * You have a working WordPress site based on either the [WordPress Composer](/tutorials/wordpress/composer),
    [Bedrock](/tutorials/wordpress/bedrock), or
    [WordPress Vanilla](/tutorials/wordpress/vanilla) guides.
  * WordPress is installed in the web/public root of the site and not in a subdirectory of its own (or in the default of
    `wp` if you set up a Bedrock-based site)
  * You know if you are creating a
    [subdirectory-based multisite or a sub/multi-domain based multisite](https://developer.wordpress.org/advanced-administration/multisite/prepare-network/#types-of-multisite-network).
</Info>

## 1. Add rewrite rules to your root location

If you are setting up a subdirectory-based multisite, or you followed the Bedrock guide, the following rewrite rules are
**required**. If you followed the Composer based or Vanilla guides and are unsure, or if you think you might convert to
a subdirectory-based multisite later, you can add these rules to a sub/multi-domain multisite without any negative
effects.

Locate the `web:locations` section in your `.upsun/config.yaml` file and update the rules section for your root (`/`)
location as follows:

<CodeGroup>
  ```yaml Vanilla, Composer theme={null}
  applications:
    myapp:
      # ...
      web:
        locations:
          "/":
            # ...
            rules:
              ^/license\.text$:
                allow: false
              ^/readme\.html$:
                allow: false
              '^/([_0-9a-zA-Z-]+/)?wp-(?<wproot>[a-z\-]+).php$':
                allow: true
                scripts: true
                passthru: '/wp-$wproot.php'
              # Allows directory-based multisites to still access the wp-admin and wp-include locations
              '^/([_0-9a-zA-Z-]+/)?(?<adminrewrite>wp-(admin|includes).*)':
                allow: true
                scripts: true
                passthru: '/$adminrewrite'
              '^/([_0-9a-zA-Z-]+)/wp-content/(?<content>.*)':
                allow: true
                scripts: false
                passthru: '/wp-content/$content'
                expires: 1w
  ```

  ```yaml Bedrock theme={null}
  applications:
    myapp:
      # ...
      web:
        locations:
          "/":
            # ...
            rules:
              ^/license\.text$:
                allow: false
              ^/readme\.html$:
                allow: false
              '^/(?!wp/)([_0-9a-zA-Z-]+/)?wp-(?<wproot>[a-z\-]+).php$':
                allow: true
                scripts: true
                passthru: '/wp/wp-$wproot.php'
              # Allows directory-based multisites to still access the wp-admin and wp-include locations
              '^/(?!wp/)([_0-9a-zA-Z-]+/)?(?<adminrewrite>wp-(admin|includes).*)':
                allow: true
                scripts: true
                passthru: '/wp/$adminrewrite'
              '^/([_0-9a-zA-Z-]+)/wp-content/(?<content>.*)':
                allow: true
                scripts: false
                passthru: '/wp-content/$content'
                expires: 1w
  ```
</CodeGroup>

<Info>
  If you followed the Bedrock guide and decided to change the default name of the directory where WordPress is installed
  (`wp`), then you will need to update both the rules and `passthru` keys accordingly.
</Info>

## 2. Update the database during the deploy hook

The domain(s) of your multisite are stored in the database itself. This creates a challenge in a system like Upsun where
you often create [preview environments](/docs/glossary#preview-environment) dynamically during development. To ensure
the database for your preview environments is updated with the correct domains, we have created a
[wp-cli package](https://github.com/upsun/wp-ms-dbu) to automate the process of updating the database with the preview
environment's unique domain name.

To install the wp-cli package, locate the `build:` section and update it as follows:

```yaml .upsun/config.yaml theme={null}
applications:
  myapp:
    <snip>
    hooks:
      build: |
        set -eux
        composer install --prefer-dist --optimize-autoloader --apcu-autoloader --no-progress --no-ansi --no-interaction
        wp package install upsun/wp-ms-dbu
        wp package update upsun/wp-ms-dbu
```

<Info>
  If you created your site based on the WordPress Vanilla guide, only add the lines above that start with `wp package`
  (i.e. skip the `composer install` line).
</Info>

To instruct the package to update your database with the relevant domains for the preview environment, locate the
`deploy` section and update it as follows:

```yaml .upsun/config.yaml theme={null}
applications:
  myapp:
    <snip>
    hooks:
      deploy: |
        set -eu
        # we need the main production url
        PRODURL=$(echo $PLATFORM_ROUTES | base64 --decode | jq -r --arg app "${PLATFORM_APPLICATION_NAME}" '[.[] | select(.primary == true and .type == "upstream" and .upstream == $app )] | first | .production_url')
        if [ 'production' != "${PLATFORM_ENVIRONMENT_TYPE}" ] &&  wp site list --format=count --url="${PRODURL}" >/dev/null 2>&1; then
          echo "Updating the database...";
          wp ms-dbu update --url="${PRODURL}"
        else
          echo "Database appears to already be updated. Skipping.";
        fi
        # Flushes the object cache
        wp cache flush
        # Runs the WordPress database update procedure
        wp core update-db
```

## 3. `wp-config.php` / `config/application.php`

Once our multisite has been set up, we need to expose additional pieces of information inside our `wp-config.php` (or
`./config/application.php` for Bedrock) file. In your wp-config.php/application.php file, right above the section
outlined below:

<CodeGroup>
  ```php wp-config.php (Vanilla, Composer) theme={null}
  /** Absolute path to the WordPress directory. */
  if ( ! defined( 'ABSPATH' ) ) {
    define( 'ABSPATH', dirname( __FILE__ ) . '/' );
  }
  ```

  ```php config/application.php (Bedrock) theme={null}
  /**
  * Bootstrap WordPress
    */
    if (!defined('ABSPATH')) {
    define('ABSPATH', $webroot_dir . '/wp/');
    }
  ```
</CodeGroup>

add the following:

<CodeGroup>
  ```php wp-config.php (Vanilla, Composer) theme={null}
  /**
   * Multisite support
   */
  define('WP_ALLOW_MULTISITE', true); //enables the Network setup panel in Tools
  define('MULTISITE', false); //instructs WordPress to run in multisite mode

  if( MULTISITE && WP_ALLOW_MULTISITE) {
  	define('SUBDOMAIN_INSTALL', false);
  	define('DOMAIN_CURRENT_SITE', parse_url(filter_var(getenv('DOMAIN_CURRENT_SITE'),FILTER_VALIDATE_URL),PHP_URL_HOST));
  	define('PATH_CURRENT_SITE', '/');
  	define('SITE_ID_CURRENT_SITE', 1);
  	define('BLOG_ID_CURRENT_SITE', 1);

  	/**
  	 * we have a sub/multidomain multisite, and the site currently being
  	 * requested is not the default domain, so we'll need to set
  	 * COOKIE_DOMAIN to the domain being requested
  	 */
  	if (SUBDOMAIN_INSTALL && $site_host !== DOMAIN_CURRENT_SITE) {
  		define('COOKIE_DOMAIN',$site_host);
  	}
  }
  ```

  ```php config/application.php (Bedrock) theme={null}
  /**
  * Multisite support
  */
  define('WP_ALLOW_MULTISITE', true); //enables the Network setup panel in Tools
  define('MULTISITE', false); //instructs WordPress to run in multisite mode

  if( MULTISITE && WP_ALLOW_MULTISITE) {
    define('SUBDOMAIN_INSTALL', false);
    define('DOMAIN_CURRENT_SITE', parse_url(filter_var(getenv('DOMAIN_CURRENT_SITE'),FILTER_VALIDATE_URL),PHP_URL_HOST));
    define('PATH_CURRENT_SITE', '/');
    define('SITE_ID_CURRENT_SITE', 1);
    define('BLOG_ID_CURRENT_SITE', 1);

    if (SUBDOMAIN_INSTALL && getenv('PLATFORM_RELATIONSHIPS')) {
        $site_host = $_SERVER['HTTP_HOST']) ??  "";
        try {
            $validURLs = json_decode(getenv('UPSTREAM_URLS'), true, 512, JSON_THROW_ON_ERROR);
        } catch (\JsonException $exception) {
            $validURLs = [];
            error_log($exception->getMessage());
        }

        if(!in_array($site_host, array_map(static function (string $url) {
            return parse_url($url, PHP_URL_HOST);
        }, $validURLs), true)) {
            $site_host = parse_url(filter_var(getenv('DOMAIN_CURRENT_SITE'),FILTER_VALIDATE_URL),PHP_URL_HOST);
        }
        /**
         * we have a sub/multidomain multisite, and the site currently being
         * requested is not the default domain, so we'll need to set
         * COOKIE_DOMAIN to the domain being requested
         */
        if ($site_host !== DOMAIN_CURRENT_SITE) {
            define('COOKIE_DOMAIN',$site_host);
        }
    }

  }
  ```
</CodeGroup>

`SUBDOMAIN_INSTALL` should be set to `true` if your multisite is a sub/multi-domain site, or `false` if you will be
setting up a subdirectory-based multisite. Note that `MULTISITE` is currently set to `false`; we will update this once
the database has finished being set up for the multisite.

## 4. Commit and push

You can now commit all the changes made above `.upsun/config.yaml` and push to Upsun.

```bash Terminal theme={null}
git add wp-config.php .environment .upsun/config.yaml
git commit -m "Add changes to begin setup of my Upsun WordPress multisite"
upsun push -y
```

## 5. Network (Multisite) Setup

Adding `define('WP_ALLOW_MULTISITE', true);` will enable the **Network Setup** item in your **Tools menu**. Use that
menu item to go to the **Create a Network of WordPress Sites** screen. Follow the instructions on this screen and click
the **Install** button. You can ignore the instructions on the resulting screen.

<Note>
  Alternatively, you can access a terminal session in the app container (`upsun ssh`), and use
  `wp core multisite-convert` to install the multisite.
</Note>

## 6. Final change to `wp-config.php` / application.php

Return to your wp-config.php / application.php file and change

```php theme={null}
define('MULTISITE', false);
```

to

```php theme={null}
define('MULTISITE', true);
```

Add and commit the changes, then push to Upsun:

```shell Terminal theme={null}
git add wp-config.php
git commit -m "set WordPress to run in multisite mode."
upsun push -y
```

Once the site has finished deploying, you can return to the Network Admin --> Sites area of wp-admin and begin adding your
sites.
