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:
- Could the codebase be made open source at any moment, without compromising any credentials?
- 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
- Codebase
- Dependencies
- Config
- Backing Services
- Build, release, run
- Processes
- Port binding
- Concurrency
- Disposability
- Dev/prod parity
- Logs
- 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.