Back to blog

Advanced hardening: isolating wp-config.php outside web root

3/8/2026 · 3 min · Cybersecurity

Share

🛡️ Advanced hardening: isolating wp-config.php outside web root

wp-config.php is the core trust file of a WordPress installation. It stores security keys and database credentials. Keeping it inside public web root (public_html or www) increases risk: if webserver parsing fails, its content may be exposed as plain text.

This guide documents the exact production workflow I use to isolate this file safely, with validation and rollback.

---

1. Configuration isolation concept

The strategy is to move the file one level above web root. If your public root is /home/accountuser/public_html/, move wp-config.php to /home/accountuser/.

Because this parent path is not served over HTTP/HTTPS, direct web access is blocked by design.

Immediate technical gains

  1. Lower exposure to automated recon.
  2. Extra protection against accidental file disclosure.
  3. Cleaner separation between public code and secrets.

---

2. Native WordPress relocation method

WordPress supports this natively: if wp-config.php is missing in web root, it checks the parent directory.

Operational procedure

  1. Full backup
  1. Server access
  1. WordPress root confirmation
  1. Move file
cd /home/accountuser/
cp public_html/wp-config.php public_html/wp-config.php.bak.$(date +%F-%H%M)
mv public_html/wp-config.php ./wp-config.php
  1. Syntax validation
php -l /home/accountuser/wp-config.php
  1. Functional validation

In standard layouts, no index.php editing is required.

---

3. Custom path method (stub loader)

If you want a specific secure path (for example, /home/accountuser/config/wp-config.php), use a lightweight root stub.

Recommended flow

  1. Move real config:
mkdir -p /home/accountuser/config
mv /home/accountuser/public_html/wp-config.php /home/accountuser/config/wp-config.php
  1. Create minimal public_html/wp-config.php:
<?php
/** Load config from a secure directory */
require_once('/home/accountuser/config/wp-config.php');

This avoids editing index.php and lowers upgrade breakage risk.

Stub security checklist

  1. Correct absolute path in require_once.
  2. Real config outside public directory.
  3. App and admin path tested after change.

---

4. OS-level hardening with file permissions

Relocation alone is insufficient if permissions remain weak.

Recommended permissions

Most restrictive mode:

chmod 400 /home/accountuser/config/wp-config.php

If web process needs group-read:

chmod 440 /home/accountuser/config/wp-config.php

Immutable protection

chattr +i /home/accountuser/config/wp-config.php
Operational warning: remove immutable flag before maintenance: chattr -i /home/accountuser/config/wp-config.php.

---

5. Post-hardening validation

After applying isolation, I run this validation cycle:

  1. php -l on final config file.
  2. HTTP response check for site and /wp-admin.
  3. Media upload and plugin update test.
  4. Log review (error_log, php-fpm.log, apache/nginx logs).

Quick probe:

curl -I https://domain.tld/
curl -I https://domain.tld/wp-login.php

Expected: normal app behavior, no config disclosure.

---

6. Common field issues

Issue A: white screen after move

Common causes:

  1. wrong require_once path;
  2. incompatible permission model;
  3. typo introduced in config.

Fix:

  1. run php -l;
  2. fix ownership/permissions;
  3. restore backup immediately.

Issue B: cache/WAF plugin behaves unexpectedly

Cause:

bootstrap order or constant load mismatch in custom stub layout.

Fix:

  1. purge caches;
  2. verify bootstrap order;
  3. validate constants through controlled test script.

---

7. Rollback plan

Keep rollback ready before any change:

mv /home/accountuser/wp-config.php /home/accountuser/public_html/wp-config.php
# or in stub scenario:
cp /home/accountuser/public_html/wp-config.php.bak.YYYY-MM-DD-HHMM /home/accountuser/public_html/wp-config.php

Then:

  1. validate syntax;
  2. reload web/PHP services if needed;
  3. retest home/admin.

---

🏁 Strategic conclusion

Moving wp-config.php outside web root adds a critical barrier against credential exposure and limits blast radius in parser misconfiguration scenarios.

It is simple, but high-impact when combined with:

  1. strict permissions (400/440);
  2. immutable flag (chattr +i);
  3. operational validation and rollback discipline.

This is the difference between a functional WordPress setup and a resilient production-grade infrastructure.

CC BY-NC

This post is licensed under CC BY-NC.

Comments

Join the discussion below.