Contents
Why use environment variables and dotenv for credentials in WordPress
Using environment variables (env vars) or a dotenv (.env) file to store credentials and configuration for WordPress separates secrets from code, reduces the risk of accidentally committing passwords to a VCS, allows different values per environment (development, staging, production), and simplifies automated deployments. Environment-based configuration is a best practice for 12-factor apps and applies to WordPress as well.
High-level approaches
- System environment variables: Set variables at the OS, web server, PHP-FPM, container, or hosting provider level and read them from PHP using getenv(), _ENV or _SERVER.
- .env files with a loader (dotenv): Keep a local .env file (ignored by Git) and load into the process environment at runtime with a library (commonly vlucas/phpdotenv) before WP uses the values.
- Secret managers: Use cloud secret managers (AWS Secrets Manager, Azure Key Vault, GCP Secret Manager) and inject secrets into env vars at deploy time or fetch them at runtime.
Security and operational considerations
- Never commit .env files to your repository. Add .env to .gitignore and maintain a .env.example with keys but no secrets.
- Place .env outside the webroot when possible (for example, if WordPress is in /var/www/html, place .env in /var/www and load it from wp-config.php). If it must be in the webroot, protect it with server config (.htaccess deny or nginx rules) so it cannot be served.
- Restrict file permissions and ownership. Typical permissions: 640 or 600 for .env and ownership by the deploy user or the PHP user as appropriate.
- Do not echo secrets to logs or error screens. Use safe logging and only show debug info in development.
- Rotate credentials periodically and have a mechanism to update env vars in hosted environments (CI/CD, deploy scripts, secret manager integration).
- Use HTTPS for external secret fetching and authenticated access for secret stores.
Which WordPress items to put in environment variables
Typical items stored in environment variables include:
- Database credentials: DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, DB_CHARSET, DB_COLLATE
- Authentication unique keys and salts
- WP_DEBUG, WP_ENV or WP_STAGE, WP_HOME, WP_SITEURL
- API keys (payment gateways, third-party services)
- File storage credentials (S3 keys), SMTP credentials, etc.
Installing and using vlucas/phpdotenv (recommended loader)
vlucas/phpdotenv is a widely used package for loading .env files into the process environment. Use Composer to add it to your project and load the autoloader early in wp-config.php before WordPress constants are defined.
Install with Composer
composer require vlucas/phpdotenv
Example .env file (store outside VCS)
# .env (do NOT commit) DB_NAME=wordpress_db DB_USER=wp_user DB_PASSWORD=S3cur3P@ssw0rd DB_HOST=127.0.0.1 WP_ENV=development WP_DEBUG=true WP_HOME=https://example.local WP_SITEURL=https://example.local/wp AUTH_KEY=put-your-long-random-string-here SECURE_AUTH_KEY=... LOGGED_IN_KEY=... NONCE_KEY=... # other secrets such as API keys STRIPE_KEY=sk_live_...
Basic wp-config.php bootstrap to load .env with vlucas/phpdotenv
Place this at the top of wp-config.php as early as possible (before defining DB constants and before requiring wp-settings.php).
safeLoad() // or dotenv->load() to require the file } catch (Exception e) { // Optionally handle the exception in deployment environments // For production you might prefer not to display errors } } // Helper to get env var with fallback function env(key, default = null) { value = getenv(key) if (value === false) { if (isset(_SERVER[key])) { value = _SERVER[key] } elseif (isset(_ENV[key])) { value = _ENV[key] } else { value = default } } return value } // Define database constants from environment variables with fallbacks define(DB_NAME, env(DB_NAME, database_name_here)) define(DB_USER, env(DB_USER, username_here)) define(DB_PASSWORD, env(DB_PASSWORD, password_here)) define(DB_HOST, env(DB_HOST, localhost)) define(DB_CHARSET, env(DB_CHARSET, utf8)) define(DB_COLLATE, env(DB_COLLATE, )) // Authentication unique keys and salts define(AUTH_KEY, env(AUTH_KEY, put your unique phrase here)) define(SECURE_AUTH_KEY, env(SECURE_AUTH_KEY, put your unique phrase here)) define(LOGGED_IN_KEY, env(LOGGED_IN_KEY, put your unique phrase here)) define(NONCE_KEY, env(NONCE_KEY, put your unique phrase here)) define(AUTH_SALT, env(AUTH_SALT, put your unique phrase here)) define(SECURE_AUTH_SALT, env(SECURE_AUTH_SALT, put your unique phrase here)) define(LOGGED_IN_SALT, env(LOGGED_IN_SALT, put your unique phrase here)) define(NONCE_SALT, env(NONCE_SALT, put your unique phrase here)) // Site URLs and environment define(WP_HOME, env(WP_HOME, http://example.com)) define(WP_SITEURL, env(WP_SITEURL, http://example.com/wp)) define(WP_ENV, env(WP_ENV, production)) define(WP_DEBUG, filter_var(env(WP_DEBUG, false), FILTER_VALIDATE_BOOLEAN)) // Proceed with the rest of wp-config.php...
Advanced dotenv usage and multiple environment files
Common pattern: keep a .env.example in source control with keys but without secrets have per-environment files like .env.development or .env.production. Load files conditionally:
safeLoad()
Where to place .env (practical tips)
- Outside webroot, e.g. if site is at /var/www/html, place .env in /var/www and create code in wp-config.php to load it via Dotenv::createImmutable(/var/www).
- If hosting provider (e.g., managed WordPress) supports defining environment variables in the dashboard, prefer that over a .env file.
- In containers, use Docker secrets or pass env vars via docker-compose or Kubernetes secrets (see examples below).
Examples for different hosting/deployment environments
Docker / docker-compose example
docker-compose with .env file or environment: use an env_file or environment section and ensure wp-config.php loads env vars.
version: 3.8 services: wordpress: image: wordpress:php8.1-fpm env_file: - .env volumes: - ./html:/var/www/html depends_on: - db db: image: mariadb:10.6 environment: MYSQL_DATABASE: {DB_NAME} MYSQL_USER: {DB_USER} MYSQL_PASSWORD: {DB_PASSWORD} MYSQL_ROOT_PASSWORD: {MYSQL_ROOT_PASSWORD}
# Dockerfile snippet (example) FROM php:8.1-fpm WORKDIR /var/www/html COPY --from=composer:latest /usr/bin/composer /usr/bin/composer COPY . /var/www/html RUN composer install --no-dev --prefer-dist --no-interaction
PHP-FPM / systemd: ensure PHP sees environment variables
By default, PHP-FPM clears the environment for security (clear_env = yes). To pass environment variables to PHP-FPM, add env[] entries in the pool config (www.conf) or set clear_env = no and ensure the required variables are exported in the system environment (e.g., via systemd service drop-in).
/etc/php/8.1/fpm/pool.d/www.conf clear_env = no env[DB_NAME] = wordpress_db env[DB_USER] = wp_user env[DB_PASSWORD] = S3cur3P@ssw0rd
Or in systemd, create an override file to set environment variables for php-fpm:
# /etc/systemd/system/php8.1-fpm.service.d/env.conf [Service] Environment=DB_NAME=wordpress_db DB_USER=wp_user DB_PASSWORD=S3cur3P@ssw0rd # Then reload and restart: systemctl daemon-reload systemctl restart php8.1-fpm
Apache example
Use SetEnv in your VirtualHost (not in .htaccess by default) so PHPs getenv() can read it when mod_php is used or when PHP-FPM picks it up via mod_proxy_fcgi depending on configuration.
ServerName example.com DocumentRoot /var/www/html SetEnv DB_NAME wordpress_db SetEnv DB_USER wp_user SetEnv DB_PASSWORD S3cur3P@ssw0rd
Nginx PHP-FPM (fastcgi) example
When using php-fpm behind nginx, you typically set env vars in php-fpm pool config or systemd as shown above. You can also pass custom fastcgi_param values to the PHP process, but fastcgi_param only sets FastCGI variables, not environment variables by default. In php-fpm config, ensure clear_env is set properly.
server { listen 80 server_name example.com root /var/www/html location ~ .php { fastcgi_pass unix:/run/php/php8.1-fpm.sock include fastcgi_params fastcgi_param SCRIPT_FILENAME document_rootfastcgi_script_name # fastcgi_param can add values to _SERVER but not always to getenv() fastcgi_param WP_ENV production } }
Using system secret managers and CI/CD
- In CI/CD pipelines, inject env vars from your secret store into the build/deploy environment (GitHub Actions secrets, GitLab CI variables, CircleCI env vars). Do not write secrets to logs or files that may be archived.
- On cloud hosts, use platform-specific methods to set env vars (Heroku config vars, AWS ECS task definitions environment variables or secrets, Kubernetes secrets mounted as env or files).
- If using Kubernetes, mount secrets as environment variables or files and ensure your wp-config.php loads from the correct path. Prefer mounting secrets as files with restrictive permissions or use tools like External Secrets to sync secrets from a manager.
WP-CLI and environment variables
WP-CLI inherits environment variables from the shell that runs it. For local development, you can run:
export DB_NAME=wordpress_db export DB_USER=wp_user export DB_PASSWORD=S3cur3P@ssw0rd wp core install --url=https://example.local --title=Example --admin_user=admin --admin_password=adminpass --admin_email=you@example.com
Alternatively, set a .wp-cli/config.yml file for non-secret settings and rely on env vars for secrets.
Generating and storing WP salts securely
WordPress salts should be long random strings. You can generate them using the WordPress secret-key service and place them in .env or set them as environment variables in your host/CI:
# Generate keys (example: curl to the WP secret-key service) curl -s https://api.wordpress.org/secret-key/1.1/salt/
Store the returned constants as environment variables on your server or in .env, then reference them in wp-config.php as shown earlier. Avoid exposing salts publicly.
Troubleshooting and common pitfalls
- Autoload path wrong: If vendor/autoload.php isnt found, Composer may be installed in a parent directory or not run. Ensure Composer install is executed in the correct path and require is correct in wp-config.php.
- Loading dotenv too late: WordPress bootstraps after wp-config.php. If you load env vars after constants are already defined, changes wont apply. Load dotenv at the top of wp-config.php before any define() calls for DB constant values.
- clear_env in PHP-FPM: If environment variables arent visible in PHP, check php-fpm pool config clear_env setting and ensure env[] or systemd Environment is configured for the PHP-FPM process.
- variables_order and _ENV: PHPs variables_order configuration affects whether _ENV is populated. getenv() tends to be more reliable for env vars, but phpdotenv also populates _ENV and _SERVER if configured.
- Defining constants twice: WordPress will throw notices or ignore redefinitions. Use defined(DB_NAME) checks or load envs before any definitions.
- Accidentally committed .env: If you commit secrets, rotate them immediately and remove the file from history (use git filter-repo or BFG) and update .gitignore.
Step-by-step implementation checklist
- Add vlucas/phpdotenv via Composer and run composer install.
- Create a .env.example file with the keys but not real secrets add .env to .gitignore.
- Create your .env (local development) with secret values or configure environment variables on the server/platform.
- Load the Composer autoloader and dotenv at the top of wp-config.php before defining constants.
- Define DB and other WP constants using getenv() or a small env() helper with fallbacks and validation where appropriate.
- Protect .env files with file permissions and server rules. Consider placing .env outside the webroot.
- Test locally, then test in staging and production. Verify that WP sees the correct values (e.g., via WP-CLI or a secure debug page) and that no secrets are exposed.
- Implement rotation and deployment processes to update environment variables or secrets via your CI/CD or hosting provider.
Examples of safer patterns and validation
Its wise to fail fast in non-production environments if required env vars are missing. Example: throw an error in development, but in production you may want to log and fail gracefully. Also validate types for booleans and integers.
Examples: Using cloud secret managers (conceptual)
Instead of .env files, you can fetch secrets from a cloud provider at deploy time and inject them into environment variables. Example pattern:
- At deploy time, the CI/CD pipeline calls AWS Secrets Manager to fetch DB credentials, then injects them into the container environment or sets env vars on the server.
- On Kubernetes, use a Kubernetes secret created from the secret manager and mount it as environment variables or files. Ensure RBAC and encryption of secrets at rest and in transit.
Reference table: typical env var names and WP constants
Environment variable | WP constant / usage |
DB_NAME | DB_NAME (database name) |
DB_USER | DB_USER (database user) |
DB_PASSWORD | DB_PASSWORD (database password) |
DB_HOST | DB_HOST (database host:port/unix socket) |
WP_ENV | Custom environment indicator (development/staging/production) |
WP_DEBUG | Controls WP_DEBUG boolean |
WP_HOME / WP_SITEURL | WP_HOME and WP_SITEURL constants |
AUTH_KEY, SECURE_AUTH_KEY, etc. | WordPress salts and authentication keys |
Third-party API keys | Plugin and integration credentials |
Final best practices (short list)
- Load secrets before WordPress constants are defined (top of wp-config.php).
- Keep secrets out of VCS use .env in development and platform/CI-managed env vars in production.
- Restrict access and permissions to secret files place .env outside webroot when possible.
- Prefer secret managers for production use env vars as the runtime mechanism.
- Validate presence of required variables and be conservative about debug output in production.
Quick implementation recipe
- composer require vlucas/phpdotenv
- Create .env (or configure platform env vars)
- Load composer autoload and Dotenv at the top of wp-config.php and map env vars to WP constants
- Protect and rotate secrets test the site and deployment pipeline
Useful patterns you can adopt immediately
- Keep a .env.example in repo, but not .env
- Use safeLoad() in production so missing local .env does not break automated deployments when you rely on platform env vars
- Use WP_ENV to switch behavior (caching, debugging, error display) between environments
- Use secret managers where available and inject into env vars at deploy time
This article contains practical examples, server and container snippets, and deployment guidance so you can adopt environment variables and dotenv in WordPress safely and consistently. Implement the patterns that match your hosting and operational model, validate on staging, and ensure secrets are rotated and protected.
|
Acepto donaciones de BAT's mediante el navegador Brave :) |