Storing Wordpress configuration in environment variables

Published by at 22nd September 2019 6:00 pm

Wordpress configuration can be a serious pain in the proverbial. Hard-coding configuration details in a PHP file is not a terribly safe way of storing the details for your database, as if the server is misconfigured they can be exposed. In addition, it can be a chore to copy and populate the wp-config.php file to a new deploy.

A fundamental principle of The Twelve-Factor App is that config should be stored in the environment. While Wordpress does predate this, there's no reason why we can't abide by this. Storing Wordpress configuration in environment variables rather than the wp-config.php file has the following advantages:

  • It's more secure since the config is not stored in a file in the web root, but in the web server config
  • It makes managing the wp-config.php file less of a chore - it can be safely committed to version control, and you won't need to change it to match your local configuration, running the risk of accidentally committing and pushing to production with broken config
  • Deployment to new servers is simpler because there's no need to update the wp-config.php
  • The risk of neglecting to change the database details and accidentally messing up the production database when working locally is virtually eliminated

I've seen solutions for this that use DotEnv, but you don't actually need to install that to be able to use environment variables with Wordpress. In fact, in some way it's better if you don't as too many developers use .env files in production. PHP natively has the ability to get data from environment variables using the getenv() function, so it's easier to use that than to pull in a third-party library.

Here's an abbreviated example of a wp-config.php file that's been updated to pull the settings from environment variables:

1<?php
2// ** MySQL settings - You can get this info from your web host ** //
3/** The name of the database for WordPress */
4define( 'DB_NAME', getenv('DB_NAME') );
5
6/** MySQL database username */
7define( 'DB_USER', getenv('DB_USER') );
8
9/** MySQL database password */
10define( 'DB_PASSWORD', getenv('DB_PASSWORD') );
11
12/** MySQL hostname */
13define( 'DB_HOST', getenv('DB_HOST') );
14
15/** Database Charset to use in creating database tables. */
16define( 'DB_CHARSET', 'utf8' );
17
18/** The Database Collate type. Don't change this if in doubt. */
19define( 'DB_COLLATE', '' );
20
21define( 'AUTH_KEY', getenv('AUTH_KEY') );
22define( 'SECURE_AUTH_KEY', getenv('SECURE_AUTH_KEY') );
23define( 'LOGGED_IN_KEY', getenv('LOGGED_IN_KEY') );
24define( 'NONCE_KEY', getenv('NONCE_KEY') );
25define( 'AUTH_SALT', getenv('AUTH_SALT') );
26define( 'SECURE_AUTH_SALT', getenv('SECURE_AUTH_SALT') );
27define( 'LOGGED_IN_SALT', getenv('LOGGED_IN_SALT') );
28define( 'NONCE_SALT', getenv('NONCE_SALT') );
29
30$table_prefix = 'wp_';
31
32define( 'WP_DEBUG', getenv('WP_DEBUG') );
33
34/* That's all, stop editing! Happy publishing. */
35
36/** Absolute path to the WordPress directory. */
37if ( ! defined( 'ABSPATH' ) ) {
38 define( 'ABSPATH', dirname( __FILE__ ) . '/' );
39}
40
41/** Sets up WordPress vars and included files. */
42require_once( ABSPATH . 'wp-settings.php' );

If you're using Lando for local development, you will need to specify a file to include that contains the environment variables you wish to set, as in this example:

1name: wordpress
2recipe: wordpress
3config:
4 webroot: .
5env_file:
6 - .env

This filename can be any arbitrarily chosen name. Then, you define the values for those variables in the same way you normally would in a .env file. Here's an abbreviated example that excludes the crypto settings (though those should be placed here too):

1DB_NAME=wordpress
2DB_USER=wordpress
3DB_PASSWORD=wordpress
4DB_HOST=database
5WP_DEBUG=true
6...

This will work fine during local development, but in production, or if you're using something like Vagrant for local development, you'll want to set the environment variables in the server configuration. For Apache, this is best set in the Virtualhost configuration, although you should be able to set it in an .htaccess file if all else fails. You need to use the SetEnv directive, as in this example:

1SetEnv DB_NAME wordpress
2SetEnv DB_USER wordpress
3SetEnv DB_PASSWORD wordpress
4SetEnv DB_HOST database
5SetEnv WP_DEBUG true

For Nginx, assuming you're using FastCGI, you need to set it in the server configuration for that site using the fastcgi_param directive, as shown below:

1fastcgi_param DB_NAME wordpress;
2fastcgi_param DB_USER wordpress;
3fastcgi_param DB_PASSWORD wordpress;
4fastcgi_param DB_HOST database;
5fastcgi_param WP_DEBUG true;

Since Wordpress doesn't ship with any kind of command-line task runner, this should be sufficient for most installs. However, if you're using WP CLI, that will break it as it won't have access to environment variables set by Apache or Nginx, so you'll also need to set them for the user that runs WP CLI by adding them to their Bash config in the usual way.