Twelve-Factor WordPress App #3: Config

Factor #3: Config

Store config in the environment

An app’s config is everything that is likely to vary between deploys (staging, production, developer environments, etc). This includes:

  • Resource handles to the database, Memcached, and other backing services
  • Credentials to external services such as Amazon S3 or Twitter
  • Per-deploy values such as the canonical hostname for the deploy

This once again starts to conflict with the normal WordPress way of doing things (a sign that we're onto something good). wp-config.php is usually treated as a catch-all for any configuration variables. But to be a proper Twelve-Factor App, anything that is likely to vary shouldn't be included in that file.

Note that this definition of “config” does not include internal application config. This type of config does not vary between deploys, and so is best done in the code.

This means that wp-config.php has its place and certain things should be included in code. It's important to know what belongs and what doesn't.

Decisions

Let's look at some things that should be included in your standard WP wp-config.php:

define('CONTENT_DIR', '/app');
define('WP_CONTENT_DIR', dirname(__FILE__) . CONTENT_DIR);
define('WP_CONTENT_URL', 'http://' . $_SERVER['HTTP_HOST'] . CONTENT_DIR);
define('DB_CHARSET', 'utf8');
$table_prefix = 'wp_';

All of these pass the 2 tests:

  1. Could the codebase be made open source at any moment, without compromising any credentials?
  2. Does it vary between deploys/environments?

And here's a few things that should not be included:

  • DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY, AUTH_SALT, SECURE_AUTH_SALT, LOGGED_IN_SALT, NONCE_SALT

Not only should these constants vary between environments, you definitely wouldn't include them if you were open sourcing your codebase.

In Practice

The twelve-factor app stores config in environment variables (often shortened to env vars or env). Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally;

So if we're not including our database credentials, for example, in our WP config, we need to store them in environment variables.

Environment variables are a set of dynamic named values that can affect the way running processes will behave on a computer.

If you're familiar with Linux, you've probably seen variables like $HOME or $PATH. Those are env vars.

You can assign them from the command line like this:

export DB_NAME=wp

Or prefix a command with them to exported as real env vars to the program:

MYSQL_TCP_PORT=3306 mysql

Database Credentials

Let's complete the example of moving WordPress DB credentials from wp-config.php to env vars.

First, we need to define all the env vars we'll need on our server:

export DB_NAME=wp
export DB_USER=wp_user
export DB_PASSWORD=wp_pass

Now we need to make sure these variables are exposed/passed into our web server. We'll look at both Nginx (PHP-FPM) and Apache2 (mod-php) options.

Nginx

Assuming you've already got PHP-FPM setup, it means you have a working php-fpm.conf file. At the bottom you need to explicitly define which variables you want to use:

env[DB_NAME] = $DB_NAME
env[DB_USER] = $DB_USER
env[DB_PASSWORD] = $DB_PASSWORD

The $ variables just reference the variables we set in our shell using export.

Apache2

Apache2 is a bit more complicated. But the easier method is just straight defining the variables in your Virtual Host or .htaccess.

Virtual Host:

<VirtualHost hostname:80>
  ...
  SetEnv DB_NAME wp
  SetEnv DB_USER wp_user
  SetEnv DB_PASSWORD wp_pass
  ...
</VirtualHost>

.htaccess:

  SetEnv DB_NAME wp
  SetEnv DB_USER wp_user
  SetEnv DB_PASSWORD wp_pass

This has the slight annoyance that you can't re-use the variables you exported before. In this case, just skip that first step and set them straight in your Apache config.

Config

Now that your web server has the needed environment variables, we need to read in our wp-config.php.

define('DB_NAME', getenv('DB_NAME'));
define('DB_USER', getenv('DB_USER'));
define('DB_PASSWORD', getenv('DB_PASSWORD'));

getenv is probably the safest way to retrieve env vars in PHP. Note that they also might be available in $_SERVER and $_ENV.

Yes, this is a lot of work to do up-front. But once it's done and you're comfortable with it, your app becomes much more flexible.

Turning a WordPress site into a Twelve-Factor App

  1. Codebase
  2. Dependencies
  3. Config
  4. Backing Services
  5. Build, release, run
  6. Processes
  7. Port binding
  8. Concurrency
  9. Disposability
  10. Dev/prod parity
  11. Logs
  12. Admin processes

Want to turn your WordPress site into a Twelve-factor App? Bedrock is a modern WordPress stack to help you get started with the best tools and practices.

Get our latest updates & occasional tips on building better WordPress sites

Follow @rootswp on Twitter