WordPress: Store Sensitive Data as Server Environment Variables
WordPress doesn’t support .env files natively. The right pattern is to set sensitive values (API keys, tokens, license keys) as server environment variables and read them in wp-config.php with getenv(). They never touch the codebase or git history.
Apache (VPS / cPanel)
In your vhost config (e.g. /etc/apache2/sites-enabled/yoursite-le-ssl.conf):
1
2
3
4
5
6
7
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html
SetEnv MY_API_KEY your-api-key-here
SetEnv PAYMENT_SECRET your-payment-secret
</VirtualHost>
Restart Apache:
1
sudo systemctl restart apache2
Nginx + PHP-FPM
In your server block (e.g. /etc/nginx/sites-available/yoursite), pass the vars via fastcgi_param:
1
2
3
4
5
6
7
8
9
10
11
server {
server_name example.com;
root /var/www/html;
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param MY_API_KEY "your-api-key-here";
fastcgi_param PAYMENT_SECRET "your-payment-secret";
}
}
Restart Nginx and PHP-FPM:
1
sudo systemctl restart nginx php8.2-fpm
DDEV (local development)
Add vars to .ddev/config.yaml under web_environment:
1
2
3
web_environment:
- MY_API_KEY=your-local-test-key
- PAYMENT_SECRET=your-local-secret
Restart DDEV:
1
ddev restart
Read the variables in wp-config.php
Once the server var is set, read it with getenv() and fall back to a default for local if needed:
1
2
3
4
// wp-config.php
define( 'MY_API_KEY', getenv('MY_API_KEY') ?: '' );
define( 'PAYMENT_SECRET', getenv('PAYMENT_SECRET') ?: '' );
Then use the constant anywhere in your theme or plugin:
1
$key = MY_API_KEY;
Verify the variable is set
Quick PHP snippet to confirm the var is being picked up (remove after testing):
1
var_dump( getenv('MY_API_KEY') );
Or via WP-CLI:
1
wp eval "var_dump(getenv('MY_API_KEY'));"
Why not just hardcode in wp-config.php?
wp-config.php often ends up in git (or should be excluded but accidentally isn’t). Server environment variables are:
- Outside the codebase entirely
- Not visible in git history
- Per-environment by default (local, staging, prod each have their own values)