How to use PHP dotenv to Secure Your WordPress site with environment vars

This guide will walk you through the process of using PHP dotenv. We will be securing WordPress using environment variables from .env as an added layer of security. It’s good practice to never store sensitive credentials in your code.

This follows the twelve-factor app methodology for building and deploying software. Number three states that we should Store config in the environment.

There are several ways to achieve this but in this basic guide, we will try to keep things simple. The wp-config.php file is probably the most important file in your WordPress installation. This is where we define some important sensitive information like database details, debug information, and also the WordPress salts along with some other settings.

The wp-config.php file is by default located in the root of the WordPress installation, assuming of course that we are working with the default setup of WordPress right out the gate.

 

Step #1 : Moving the config file.

In this step, we will move the wp-config file one directory above the base install directory. With a default setup of WordPress we can move this file one directory up, so if you install WordPress in a directory called, app/my-website/publicwe can move the config file to the ” app/my-website/ ” directory, no change is required for this to work as WordPress will always check the next directory up if the file is not located in the base installation.

 

Step #2 : install composer packages.

If you have followed step #1 then the wp-config file should be in app/my-website/wp-config.php while the full WordPress installing will remain in app/my-website/ public/

At this point, we will use composer to pull in some packages. We want our vendor folder to live in the same directory as our wp-config file so we will install it in the app/my-website/ directory. Create a composer.json file in app/my-website/composer.json and add the following:

{
	    "require": {
	        "php": "^7.0",
	        "roots/wp-config": "1.0.0",
	        "symfony/error-handler": "^5.1",
	        "symfony/var-dumper": "^5.1.4",
	        "vlucas/phpdotenv": "^5.2"
	    },
	    "config": {
		"optimize-autoloader": true,
	        "sort-packages": true
	    }
	}
	

This is all we need from composer, lets walk through what we will install.

  1. roots/wp-config ( helps define config values with some added extras )
  2. symfony/error-handler ( not needed but will help us with debugging )
  3. symfony/var-dumper ( also optional but just a nicer version of the var_dump() function )
  4. vlucas/phpdotenv ( this is the important one and where all the goodness happens as it will give us full access to the values in .env )

You can read up more on each package here:

To install the packages from within the directory app/my-website/composer.json simply run composer install from the command line.

$ composer install

Composer will grab all the packages we defined and install them in app/my-website/vendor directory.

 

Step #3 : Add the env file

If everything went well so far we are now ready to implement our secure config file, time to add the .env file. All the settings you need will live in the .env file so create it in app/my-website/.env, please remember to not include this in version control remember to exclude it in the .gitignore file. after you create the file include the following settings.

We need to grab some WordPress Salt Keys we can get from the WordPress API or grab them from our friends over at https://roots.io/salts.html this will give us ready-made values that can just plug into our .env file. You will notice I have some other values in the .env file but some of those are optional. be sure to input the correct values for the database and site URL.

 

Step #4 : Edit The WordPress Config File

Important: before this step make sure to backup your config file somewhere, just in case everything blows up.

Okay, let’s do some config edits assuming that you have included all the settings you need in .env its time to edit the config file.

 

First thing is we need to include the composer autoloader and bring in our dependencies.

require_once  dirname( __FILE__ ) . '/vendor/autoload.php';

	use Symfony\Component\ErrorHandler\Debug;
	use Symfony\Component\ErrorHandler\ErrorHandler;
	use Symfony\Component\ErrorHandler\DebugClassLoader;
	use Roots\WPConfig\Config;
	use Dotenv\Dotenv;

 

Now let’s take it step by step.

 

Here we define our debug and we can turn this on and off, I decided to leave this value in the config file as it will be easier to work with.

define( 'WP_DEBUG', false );

 

Now let’s Add our Symfony debugger, I’ve wrapped this in a simple if statement so it only runs if we turn on the WordPress debug mode.

if ( defined('WP_DEBUG') &&  true === WP_DEBUG ) :
		Debug::enable();
	endif;

 

After that, we will initialize Dotenv to grab .env values.

$dotenv = Dotenv::createImmutable(__DIR__);
	$dotenv->load();

 

This block of code will Take care of the debugging when WP_DEBUG is set. Note also that we are now using Config::define from the Roots\WPConfig\Config package.


	if ( defined('WP_DEBUG') && false === WP_DEBUG ) :

		Config::define('WP_DEBUG_DISPLAY', false);
		Config::define('WP_DEBUG_LOG', false);
		Config::define('SCRIPT_DEBUG', false);
		ini_set('display_errors', '0');

	elseif ( defined('WP_DEBUG') &&  true === WP_DEBUG ) :

	   Config::define('SAVEQUERIES', true);
	   Config::define('WP_DEBUG_DISPLAY', true);
	   Config::define('WP_DISABLE_FATAL_ERROR_HANDLER', true);
	   Config::define('SCRIPT_DEBUG', true);
	   Config::define('WP_DEBUG_LOG', dirname( __FILE__ ) . '/tmp/wp-errors.log' );
	   ini_set('display_errors', '1');

	endif;
	

 

Define some settings for the URL. This is where we start getting values from our .env file with the help of the Dotenv\Dotenv. The defined variables are now available in the $_ENV and $_SERVER super-globals.

Config::define('WP_HOME', $_ENV['WP_HOME'] );
	Config::define('WP_SITEURL', $_ENV['WP_SITEURL'] );

 

Next, we will grab the database settings.

Config::define('DB_NAME', $_ENV['DB_NAME'] );
	Config::define('DB_USER', $_ENV['DB_USER'] );
	Config::define('DB_PASSWORD', $_ENV['DB_PASSWORD'] );
	Config::define('DB_HOST', $_ENV['DB_HOST'] ?: 'localhost');
	Config::define('DB_CHARSET', 'utf8mb4');
	Config::define('DB_COLLATE', '');
	$table_prefix = $_ENV['DB_PREFIX'];

 

Unique Keys and Salts.

Config::define('AUTH_KEY', $_ENV['AUTH_KEY'] );
	Config::define('SECURE_AUTH_KEY', $_ENV['SECURE_AUTH_KEY'] );
	Config::define('LOGGED_IN_KEY', $_ENV['LOGGED_IN_KEY'] );
	Config::define('NONCE_KEY', $_ENV['NONCE_KEY'] );
	Config::define('AUTH_SALT', $_ENV['AUTH_SALT'] );
	Config::define('SECURE_AUTH_SALT', $_ENV['SECURE_AUTH_SALT'] );
	Config::define('LOGGED_IN_SALT', $_ENV['LOGGED_IN_SALT'] );
	Config::define('NONCE_SALT', $_ENV['NONCE_SALT'] );

 

The memory section is optional but we can increase the memory limit here.

Config::define('WP_MEMORY_LIMIT', $_ENV['MEMORY_LIMIT'] );
	Config::define('WP_MAX_MEMORY_LIMIT', $_ENV['MAX_MEMORY_LIMIT'] );

 

And finally, do config apply, “this will Scan configMap to see if user is trying to redefine any constants.

Config::apply();

 

Your setup is now complete, the final wp-config.php file should look like this.