Loading...
Home
Explore
Contact
Sign in
Website

Secure wp-config.php and Server Configs: Hardening Guide

Lock down WordPress secrets and server configs before attackers scrape credentials. This guide covers real permission fixes, salt rotation, and web-server rules—plus when to book Fixwebnode server support.

Fixwebnode Support
Fixwebnode Support
10 min read 13 views
Secure wp-config.php and Server Configs: Hardening Guide

If your WordPress site stores database passwords, salts, and debug flags in plain text, a single mis-set permission or backup copy can hand an attacker the keys. This guide walks homeowners and small-business operators through hardening wp-config.php and the Apache/Nginx files that protect it—so you can reduce exposure without guessing.

Scope assumes a typical Linux VPS or shared host with shell or SFTP access (Ubuntu/Debian-style paths are shown; adjust for your stack). You will set correct ownership and modes, move secrets out of the web root where possible, rotate authentication keys, lock down directory listing and PHP in uploads, and verify nothing sensitive is still world-readable. For hands-on help, Fixwebnode server support can take over the same checklist on production hosts across Australia and remote regions we cover in our service areas.

Why hardening wp-config.php and server configs matters

WordPress loads database credentials, table prefix, and cryptographic salts from wp-config.php on every request. If that file is readable by the wrong user, left as a .bak inside the document root, or served because the web server ignores extension rules, bots harvest it within minutes of a scan. Server configuration files—Apache .htaccess / vhost conf, Nginx site blocks, PHP-FPM pool settings—decide whether directory indexes appear, whether .php runs under wp-content/uploads, and whether backup names like wp-config.php~ are blocked.

Small sites are not exempt. Automated scanners do not care about traffic volume; they care about open permissions and default paths. Hardening here is preventive maintenance, not optional polish.

Common issues that leave credentials exposed

These problems show up repeatedly on DIY WordPress installs. Each has a different root cause.

1. World-readable or group-writable wp-config.php

Symptoms: File mode shows 644, 664, or worse 666/777; ls -l lists the web user or “others” with read. Hosting scanners or security plugins flag “config file permissions insecure.” In shared hosting, neighboring accounts may read your DB password if the filesystem allows it.

2. Authentication unique keys and salts missing, default, or never rotated after a compromise

Symptoms: AUTH_KEY, SECURE_AUTH_KEY, and related defines still say “put your unique phrase here,” or you restored from backup after malware and never rotated. Users stay logged in on stolen cookies; password resets feel ineffective because cookie hashing still matches old salts.

3. Backup copies and editor swap files inside the web root

Symptoms: Files such as wp-config.php.bak, wp-config.php.old, wp-config.php.save, wp-config.php~, or .wp-config.php.swp exist under the document root. A direct HTTPS request returns the full PHP source as text because the server treats unknown extensions as static files.

4. Web server allows indexes or PHP execution under uploads

Symptoms: Visiting /wp-content/uploads/ lists filenames; a dropped shell.php in uploads executes when requested. Access logs show probes for uploads/*.php. Often caused by missing Nginx location rules or Apache php_admin_flag / handler overrides not applied to that path.

How to fix each issue step by step

Fix 1 — Correct ownership and permissions on wp-config.php

Goal: only the account that runs PHP (and root for admin) can read the file; the web process should not need write access in normal operation.

Step 1 — Identify the web/PHP user and document root

ps aux | egrep 'php-fpm|apache2|httpd|nginx' | head
whoami
pwd
ls -la wp-config.php 2>/dev/null || ls -la /var/www/html/wp-config.php

Note the user column for php-fpm or apache (often www-data, nginx, or a per-site user like siteuser).

Step 2 — Set owner and restrictive mode

sudo chown root:www-data /var/www/html/wp-config.php
sudo chmod 640 /var/www/html/wp-config.php
# If PHP runs as the site owner instead of www-data:
# sudo chown siteuser:siteuser /path/to/wp-config.php
# sudo chmod 600 /path/to/wp-config.php

Prefer 600 when the PHP worker and file owner are the same account; use 640 with group www-data when root owns the file and PHP is in that group. Never leave 777 or world-writable bits.

Step 3 — Verify no “other” read bit and that WordPress still loads

stat -c '%a %U:%G %n' /var/www/html/wp-config.php
curl -sI https://your-domain.example/ | head -n 5

Expect modes 600 or 640 and HTTP 200 on the homepage. If you get a database connection error, the PHP user cannot read the file—adjust group membership, not mode to 644.

Step 4 — Optional: move wp-config one level above the web root

WordPress automatically looks for wp-config.php in the parent of ABSPATH. If your document root is /var/www/html/public, place the file at /var/www/html/wp-config.php so the web server cannot map a URL to it even if misconfigured.

sudo mv /var/www/html/public/wp-config.php /var/www/html/wp-config.php
sudo chown root:www-data /var/www/html/wp-config.php
sudo chmod 640 /var/www/html/wp-config.php

When DIY is not enough: multi-site chroot layouts, OpenLiteSpeed, or hosts that reset permissions on deploy often need a specialist. Book Fixwebnode server support if permission changes break the site after every push.

Fix 2 — Generate and install fresh WordPress salts

Goal: invalidate old cookies and ensure every key define is long and unique.

Step 1 — Back up the current config

sudo cp -a /var/www/html/wp-config.php /root/wp-config.php.$(date +%F).bak
sudo chmod 600 /root/wp-config.php.*.bak

Keep the backup outside the web root only.

Step 2 — Fetch new salts from the official generator

curl -sS https://api.wordpress.org/secret-key/1.1/salt/

Copy the eight define(...) lines returned.

Step 3 — Replace the existing key block in wp-config.php

Edit carefully (use sudo -u appropriate editor). Remove old AUTH_KEY through NONCE_SALT lines and paste the new block. Do not break surrounding PHP syntax.

sudo nano /var/www/html/wp-config.php
# or: sudo sed -n '1,120p' /var/www/html/wp-config.php | head

Step 4 — Confirm the site loads and force re-login

php -l /var/www/html/wp-config.php
curl -sI https://your-domain.example/wp-login.php | head -n 8

php -l must report “No syntax errors.” All sessions are invalidated; admins log in again. If you suspect a prior breach, also rotate the MySQL password in both the database and the DB_PASSWORD define.

Call a pro when malware keeps rewriting wp-config.php after salt rotation—that is an integrity problem, not a one-line fix. Fixwebnode’s Secure Linux Admin & Full-Stack Infrastructure Australia work covers host-level cleanup alongside WordPress secrets.

Fix 3 — Find and remove exposed config backups

Goal: eliminate alternate filenames attackers request by dictionary.

Step 1 — Search the document root for config variants

sudo find /var/www/html -maxdepth 3 \( \
 -iname 'wp-config*.bak' -o -iname 'wp-config*.old' -o \
 -iname 'wp-config*.save' -o -iname 'wp-config*~' -o \
 -iname 'wp-config*.swp' -o -iname 'wp-config.php.txt' -o \
 -iname '.wp-config.php.swp' \
\) -ls

Step 2 — Move hits to a root-only archive, then delete after review

sudo mkdir -p /root/wp-config-quarantine
sudo find /var/www/html -maxdepth 3 \( -iname 'wp-config*.bak' -o -iname 'wp-config*.old' -o -iname 'wp-config.php.txt' \) -exec mv -t /root/wp-config-quarantine {} +
sudo chmod -R 600 /root/wp-config-quarantine

Step 3 — Block residual patterns at the web server

Apache (inside the site .htaccess or vhost):

<FilesMatch "(?i)^wp-config.*\.(bak|old|save|swp|txt|dist)$">
 Require all denied
</FilesMatch>
<Files "wp-config.php">
 Require all denied
</Files>

Note: denying wp-config.php via Files stops HTTP fetch; PHP still includes it from disk. On Nginx, prefer:

location ~* /wp-config.*\.(bak|old|save|swp|txt)$ {
 deny all;
 return 404;
}
location = /wp-config.php {
 deny all;
 return 404;
}

Reload after edit:

sudo apache2ctl configtest && sudo systemctl reload apache2
# or
sudo nginx -t && sudo systemctl reload nginx

Step 4 — Verify direct URL access fails

curl -sI https://your-domain.example/wp-config.php
curl -sI https://your-domain.example/wp-config.php.bak

Expect 403 or 404, not 200 with body length matching the file size.

If you also fight broken package mirrors after host recovery, the related runbook Fix Corrupted Linux APT Sources.list - Alabama Expert Support covers restoring clean APT sources so security updates install again—often the missing piece after a messy rebuild.

Fix 4 — Harden uploads and directory listing in server config

Goal: no autoindex; no PHP execution under user-upload paths.

Step 1 — Disable indexes for WordPress content trees (Apache)

# In the vhost or a committed .htaccess under wp-content/
Options -Indexes

Step 2 — Nginx: turn off autoindex and neutralize PHP in uploads

location /wp-content/uploads/ {
 location ~* \.php$ {
 deny all;
 return 404;
 }
 autoindex off;
}

Step 3 — Add a defensive .htaccess inside uploads (Apache/php-fpm)

printf '%s\n' \
 '<FilesMatch "\\.(?i:php|phtml|php[0-9]|phar)$">' \
 ' Require all denied' \
 '</FilesMatch>' \
 'Options -Indexes' \
 | sudo tee /var/www/html/wp-content/uploads/.htaccess
sudo chmod 644 /var/www/html/wp-content/uploads/.htaccess

Step 4 — Verify

# Should not list files:
curl -sI https://your-domain.example/wp-content/uploads/
# Drop a harmless probe only in a test env, then remove it:
echo '<?php echo "x";' | sudo tee /var/www/html/wp-content/uploads/_probe.php
curl -sI https://your-domain.example/wp-content/uploads/_probe.php
sudo rm -f /var/www/html/wp-content/uploads/_probe.php

Listing should be denied; the probe must not return 200 with PHP output.

Also disable production debug in wp-config.php if still on:

define('WP_DEBUG', false);
define('WP_DEBUG_LOG', false);
define('WP_DEBUG_DISPLAY', false);
@ini_set('display_errors', 0);

Debug logs under wp-content/debug.log can leak paths and queries if left web-accessible—remove or block that file the same way as config backups.

When DIY is enough vs when to book Fixwebnode

DIY is enough when you have shell access, a single site, clean file ownership, and the symptoms match one of the four issues above. Work from a snapshot or host backup first; change one control at a time; re-test login and checkout flows after each step.

Book a specialist when any of these apply: you cannot identify the PHP runtime user; permissions reset on every deploy or host panel “fix”; wp-config.php is rewritten by malware after you harden it; you run nested reverse proxies, LiteSpeed, or container mounts that ignore classic chmod; database credentials may already have leaked and need coordinated rotation with firewall rules; or the site is down and you need recovery plus hardening in one pass.

Fixwebnode operates as a direct specialist for server support—not a bid board. Geography and remote coverage are listed on our all service areas page, including Australian production hosts and selected remote regions. Deep Linux admin and stack lockdown is available via Secure Linux Admin & Full-Stack Infrastructure Australia.

Next step: lock the config layer with a specialist conversation

You now have a concrete path: restrict wp-config.php modes and placement, rotate salts, quarantine backup copies, and stop indexes plus PHP under uploads. Those four controls close the most common credential-leak paths on small WordPress servers.

If you want a second set of eyes on a live host—or the DIY steps conflict with your panel’s permission model—start a conversation with Fixwebnode and walk through the same checklist on your stack. Book through the landing page: server support step-by-step with Fixwebnode. Bring SSH access notes and whether you use Apache or Nginx so the session stays focused on config hardening, not guesswork.

Share this article
Fixwebnode Support
Fixwebnode Support

Hey there!
I am your assistant for Fixwebnode. Ask about our services, quotes, packages, orders, or how to get support.
While you wait
What’s your name and best email? We’ll reply even if you leave.