blog single gear
Tutorials

How to Install & Scale WordPress on Cloud Foundry in 2018

Way back in 2014, I wrote this article about how to install and run WordPress on Cloud Foundry. Since then, a lot has changed with Cloud Foundry so I’d like to suggest a new way of running WordPress on Cloud Foundry–one that’s simpler and takes advantage of new features the platform offers.

At a high level, here is what we’re going to do.

  1. Download WordPress
  2. Create a MySQL Database
  3. Create a Volume Service
  4. Configure WordPress
  5. Push WordPress & bind our two services to the app

This is a simple approach and allows WordPress to store its files on the persistent disk provided by the Volume Service. This not only provides us with an easy way to retain WordPress state across application restarts, but also provides us with a way to easily scale up the number of WordPress instances running on our platform.

Getting Started

To get started, you’ll need access to Cloud Foundry. You might have this through your employer or you can get an open source or Certified Platform account. If choosing the latter, make sure the Certified Provider supports Volume Services. Then follow these instructions to install the CF cli and these instructions to login.

Next, download the latest version of WordPress to your working directory. You can do this in your browser or if you want to be slick, you can run this command: `curl -L -o wordpress-latest.zip https://wordpress.org/latest.zip`. After the download completes, extract the files into a folder named wordpress.

In your working directory where the wordpress folder exists, but not in the wordpress folder, create a file called manifest.yml. This is an application manifest and describes how to deploy an application on Cloud Foundry.

In that file, put the following:

---
applications:
- name: wordpress
memory: 128M
path: .
route: wordpress-on.<app-domain>
buildpack: php_buildpack
services:
- wordpress-mysql-db

Replace “<app-domain>” or the entire route with the domain or route you’d like to use to access your application. If you’re unsure, you can run `cf domains` to see the domains that are available through your CF provider.

Your working directory should look like this:

Creating Services

We are now going to create the MySQL service that will be used by WordPress. You can use any MySQL DB service you like; just make sure the service name you create matches the service name in the manifest.yml. For example, `cf create-service p-mysql 100mb wordpress-mysql-db` (note now `wordpress-mysql-db` is used both here and in the manifest.yml file).

Our next step is to create the persistent disk where WordPress is going to store its themes, plugins and media uploads. This uses a new feature in Cloud Foundry called Volume Services, which through service bindings mounts a persistent volume into the container of your application as it runs on Cloud Foundry. In our example, we will create an NFS Volume Service instance, but you can use any Volume Service type available through your Cloud Foundry provider.

To create the volume service instance using the NFS Volume Service broker, run `cf create-service nfs Existing wordpress-files -c ‘{“share”: “nfs_server/path/to/nfs/files”}’`. The “nfs_server/path/to/nfs/files” is a configuration option specific to the NFS Volume Service provider, and it provides the information necessary to locate the NFS server & the exported volume where your files will live. An example of this would be `10.10.10.10/export/myshare`. If you’re unsure about what to enter here, check with your NFS administrator.

Configure WordPress

At this point, we have all the resources necessary to deploy WordPress but, before we actually deploy it, we need to do some configuration so that WordPress can find our resources. This will happen in the wp-config.php file, so go ahead and rename wp-config-sample.php to wp-config.php or run `mv wordpress/wp-config-sample.php wordpress/wp-config.php`. Now open wp-config.php in your favorite text editor.

The default configuration will contain a section where you would normally enter the database configuration (i.e. host, username, password & database name).

Because we don’t want to hard code that information into the configuration file, we’re going to replace the default database configuration section with the following code:

// ** Read MySQL service properties from _ENV['VCAP_SERVICES']
$services = json_decode($_ENV['VCAP_SERVICES'], true);
$service = $services['p-mysql'][0]; // pick the first MySQL service

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', $service['credentials']['name']);

/** MySQL database username */
define('DB_USER', $service['credentials']['username']);

/** MySQL database password */
define('DB_PASSWORD', $service['credentials']['password']);

/** MySQL hostname */
define('DB_HOST', $service['credentials']['hostname'] . ':' . $service['credentials']['port']);

/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8');

/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');

This code reads the VCAP_SERVICES environment variable, which is populated by the platform with our bound service information, and uses that to configure WordPress.

The only thing you need to adjust above is the name of the MySQL service you created (line #3). In the example above, we’re using `p-mysql` which is the same as what we used for the first argument to the `cf create-service` command in the example above. Replace this value with the name of the service provider you used when you created your service.

At this point, feel free to make any additional adjustments to your wp-config.php file. For example, you’ll probably want to adjust the authentication unique keys and salts as these should be different for every site. Once you’re satisfied with the configuration, we’ll move onto the next step which is to configure PHP.

To run WordPress we need PHP. WordPress also requires some PHP extensions so it can operate correctly, so we need those too. Normally, installing PHP is something you would need to do as the system administrator. Fortunately with Cloud Foundry, the platform takes care of this for you through the PHP buildpack.

When we push WordPress to Cloud Foundry, the PHP buildpack will run and helpfully install PHP for us. All we need to do here is to tell the buildpack which extensions to install. To do this, we create the file, and any missing directories, `.bp-config/php/php.ini.d/wp-extensions.ini` under your working directory and add the following into that file:

extension=mbstring.so
extension=mysqli.so
extension=gd.so
extension=zip.so
extension=openssl.so
extension=sockets.so

In addition, we need to tell the PHP buildpack which version of PHP to install. We can do that by creating the file `.bp-config/options.json` in our working directory. In that file, add the following:

{
"WEBDIR": "wordpress",
"PHP_VERSION": "{PHP_71_LATEST}"
}

This will tell the PHP buildpack to install the most recent version of PHP 7.1. You could optionally use `PHP_72_LATEST` if you want to use that version instead.

Our last configuration step is to seed the persistent storage with the necessary files from our WordPress download. To do this, we’ll include a short script with the application which will move the files for us.

First rename the wp-content folder to wp-content-orig or run `mv wordpress/wp-content wordpress/wp-content-orig`. Then create a file in your working directory called .profile, the leading dot is important, and open it with your favorite text editor.

In that file, add the following:

#!/bin/bash

# set path of where NFS partition is mounted
MOUNT_FOLDER="/home/vcap/app/files"

# set name of folder in which to store files on the NFS partition
WPCONTENT_FOLDER="$(echo $VCAP_APPLICATION | jq -r .application_name)"

# Does the WPCONTENT_FOLDER exist under MOUNT_FOLDER? If not seed it.
TARGET="$MOUNT_FOLDER/$WPCONTENT_FOLDER"
if [ ! -d "$TARGET" ]; then
echo "First run, moving default WordPress files to the remote volume"
mv "/home/vcap/app/wordpress/wp-content-orig" "$TARGET"
ln -s "$TARGET" "/home/vcap/app/wordpress/wp-content"

# Write warning to remote folder
echo "!! WARNING !! DO NOT EDIT FILES IN THIS DIRECTORY!!" > \
"$TARGET/WARNING_DO_NOT_EDIT_THIS_DIRECTORY"
else
ln -s "$TARGET" "/home/vcap/app/wordpress/wp-content"
rm -rf "/home/vcap/app/wordpress/wp-content-orig" # we don't need this
fi

You won’t need to modify the script, but review it if you like. When you’re done, save and close the file.

All of our configuration is now set and you should have a working directory that looks like this.

Deploy WordPress to Cloud Foundry

We’re ready to push WordPress. To do that run `cf push –no-start`. The `–no-start` option is critical as we need to bind our volume service before we actually start the app. We’ll do that next.

To bind our volume service instance to the app, we will run the command `cf bind-service <app> <volume-service-name>`. This should generally be sufficient, but depending on the type of Volume Service you may need to provide some additional configuration options using the `-c` argument to this command. For example, with an NFS Volume Service we need to specify the uid, gid and mount point.

If you’re following along and used the command above to create an NFS Volume Service, you can run `cf bind-service wordpress wordpress-files -c ‘{“uid”: “1001”, “gid”: “1001”, “mount”: “/home/vcap/app/files”}’`. Just adjust the uid and gid so they match your user and group on your NFS server. Don’t touch the mount, unless you also update the .profile script we previously created.

With the Volume Service instance bound to the app, we can now start WordPress with the command `cf start wordpress`. This will stage and start WordPress.

When the command completes, you can access the route bound to your application and perform the initial installation/configuration of WordPress.

After you perform the installation, install themes, plugins and adjust configuration, your WordPress site will be ready to use.

Upgrades, Maintenance & Scaling

As with all software, but even more so with WordPress, it’s critical that you keep everything up-to-date. Fortunately, Cloud Foundry makes this easy and these two steps should help keep your site up-to-date:

  1. When there is a new version of PHP, run `cf restage wordpress`. This will restage your application, which runs the buildpack, and the buildpack will install the latest version of PHP & all it’s extensions.
  2. When there are updates to WordPress, you can install them them through the WordPress Dashboard under the Updates section. Because WordPress updates itself like this, it’s not actually necessary to download WordPress directly or `cf push` any updates. It can all be managed through the WordPress UI.

Lastly, if the traffic to your site goes up and you need to scale WordPress to handle more load, you only need to execute `cf scale wordpress -i X` where X is the number of application instances you want to run. After that completes, you’ll have more instances of WordPress running to handle all of your user’s requests.

This is another benefit of Volume Service, because every instance of your application has access to the Volume Service instance, so persistent data is conveniently accessible to all instances. Do keep in mind that Volume Services will not scale infinitely, and at some point you will end up with a bottleneck on your Volume Service instance. At that point, you’ll need to pursue other options for scaling your WordPress site like using a CDN to offload requests.

Summary

Congratulations!  The boring part is now done. Your WordPress site is running, ready to scale as needed and easy to update, all courtesy of Cloud Foundry. This leaves you free to focus on the fun and important tasks like creating content and engaging with your users.

Daniel Mikusa Profile Image

Daniel Mikusa, AUTHOR

SEE ALL ARTICLES