Upsun User Documentation

Deploy WordPress Multisite on Upsun

Try Upsun for 15 days
After that, enjoy the same, game-changing Upsun features for less with the First Project Incentive!¹ A monthly $19 perk!
Activate your 15-day trial
¹Terms and conditions apply

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. You should also already have a working WordPress site (see Assumptions for the WordPress guides your WordPress site should be based on).

Before you begin Anchor to this heading

You need:

  • Git. 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.
  • A Upsun account. If you don’t already have one, register for a trial account. 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.
  • The Upsun CLI. This lets you interact with your project from the command line. You can also do most things through the Web Console.

1. Add rewrite rules to your root location Anchor to this heading

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:


applications:
  myapp:
    <snip>
    web:
      locations:
        "/":
          <snip>
          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


applications:
  myapp:
    <snip>
    web:
      locations:
        "/":
          <snip>
          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

2. Update the database during the deploy hook Anchor to this heading

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 dynamically during development. To ensure the database for your preview environments is updated with the correct domains, we have created a wp-cli package 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:

.upsun/config.yaml
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        

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:

.upsun/config.yaml
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 Anchor to this heading

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:

/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
  define( 'ABSPATH', dirname( __FILE__ ) . '/' );
}
/**
* Bootstrap WordPress
  */
  if (!defined('ABSPATH')) {
  define('ABSPATH', $webroot_dir . '/wp/');
  }

add the following:

/**
 * 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); // does the instance contain subdirectory sites (false) or subdomain/multiple domain sites (true)
	define('DOMAIN_CURRENT_SITE', parse_url(filter_var(getenv('DOMAIN_CURRENT_SITE'),FILTER_VALIDATE_URL),PHP_URL_HOST));
	define('PATH_CURRENT_SITE', '/'); //path to the WordPress site if it isn't the root of the site (e.g. https://foo.com/blog/)
	define('SITE_ID_CURRENT_SITE', 1); //main/primary site ID
	define('BLOG_ID_CURRENT_SITE', 1); //main/primary/parent blog ID

	/**
	 * 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);
	}
}

/**
* 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); // does the instance contain subdirectory sites (false) or subdomain/multiple domain sites (true)
  define('DOMAIN_CURRENT_SITE', parse_url(filter_var(getenv('DOMAIN_CURRENT_SITE'),FILTER_VALIDATE_URL),PHP_URL_HOST));
  define('PATH_CURRENT_SITE', '/'); //path to the WordPress site if it isn't the root of the site (e.g. https://foo.com/blog/)
  define('SITE_ID_CURRENT_SITE', 1); //main/primary site ID
  define('BLOG_ID_CURRENT_SITE', 1); //main/primary/parent blog ID

  if (SUBDOMAIN_INSTALL && getenv('PLATFORM_RELATIONSHIPS')) {
      $site_host = $_SERVER['HTTP_HOST']) ??  "";
      //we're not running locally so we need to make sure $site_host is set to something appropriate
      try {
          $validURLs = json_decode(getenv('UPSTREAM_URLS'), true, 512, JSON_THROW_ON_ERROR);
      } catch (\JsonException $exception) {
          $validURLs = [];
          error_log($exception->getMessage());
      }

      //if site_host isnt a valid domain we're expecting, then set it to the default domain
      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);
      }
  }

}

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 Anchor to this heading

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

Terminal
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 Anchor to this heading

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.

6. Final change to wp-config.php / application.php Anchor to this heading

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

define('MULTISITE', false);

to

define('MULTISITE', true);

Add and commit the changes, then push to Upsun:

Terminal
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.