RB-007 — WordPress admin lockout (security plugin / lost admin) — recover via Dokploy¶
Use this runbook when: nobody can log in to the
wp-adminof one of the Dokploy-hosted WordPress sites —tneconnect.app,eidos-global.com, orprojecteidos.com— but the public site still loads, and you hold Dokploy / container backend access. Typical triggers: a security plugin (Wordfence et al.) is locking out logins, a brute-force / 2FA / breached-password block has fired, the login URL was hidden, or the only admin accounts belong to a third party you can no longer reach.
id: RB-007
title: WordPress admin lockout — recover via Dokploy container backend
severity: high
estimated_duration: 10–20 minutes with Dokploy access
servers_affected: [E2] # all three WP sites run on E2 via Dokploy
apps_affected: ["TnE Connect WordPress", "PE WordPress", "EIDOS Global WordPress"]
related_kis: [KI-048, KI-004, KI-038]
related_incidents: [INC-2026-06-04-tneconnect-wp-lockout]
related_runbooks: []
Trigger / detection¶
All of the following are true:
- The public site loads (the front-end renders) — so this is a login-layer problem, not a host/container outage. If the whole site is down, this is not the right runbook (check E2 / Dokploy / Traefik first).
- No one can log in at
https://<site>/wp-login.php— neither you nor the developers. Symptoms vary by cause: - "You have been locked out" / brute-force block message → a security plugin's lockout.
- A previously-working password is suddenly rejected → security plugin's breached-password check, or the DB was replaced.
- A 2FA prompt no one can satisfy → security plugin's login-security / MFA enforcement.
wp-login.php404s → a hidden-login plugin changed the path.- White screen on
/wp-admin→ a plugin fatal error.
If the public site itself is down, stop — that's an E2/Dokploy/Traefik problem, not this runbook.
Severity¶
High. These are public, brand-facing marketing sites and lead-capture funnels (.app and the company domains). You retain full control of the host, so there is no data-loss risk from the lockout itself — but every minute locked out is a minute you cannot publish, fix, or respond. The deeper exposure this runbook exists to close is captured in KI-048: for these sites Eidos historically had no owned admin account at all — admin access depended entirely on the third-party dev agency.
Key principle¶
A WordPress security plugin only guards the login form. It does not guard the container filesystem or the database underneath. With Dokploy backend access you are never actually locked out — you go in below the plugin, disable it on disk, and mint yourself an admin. None of the steps below touch the public site or its content.
Required access¶
- Dokploy access to the WordPress app (today:
platform.projecteidos.com), OR SSH to E2 (145.241.230.130) withdockerrights. - The ability to open a container shell / terminal for the WordPress container (Dokploy → the app → Terminal, or
docker exec -it <container> bashon E2). - No WordPress credentials are required — that is the whole point.
Preconditions¶
| Item | Notes |
|---|---|
| Public site is up | Confirms login-layer issue, not host outage |
| Container is running | docker ps shows the WordPress container for the site |
| You can write inside the container | You are root in the container shell (the Dokploy terminal lands you as root) |
Recovery steps¶
Worked example: the 2026-06-04
tneconnect.applockout (incident). The cause there was Wordfence; substitute the actual plugin folder name for your case.
Step 1 — Open a shell in the WordPress container¶
Dokploy → the WordPress app → Terminal (or on E2: sudo docker ps to find the container, then sudo docker exec -it <id> bash). You should land as root.
Step 2 — Find the WordPress web root¶
cd /var/www/html 2>/dev/null || cd "$(dirname "$(find / -name wp-config.php 2>/dev/null | head -1)")"
pwd
ls -la wp-content/plugins
The plugin folder listing is your diagnosis. Look for security plugins: wordfence, wordfence-login-security, all-in-one-wp-security, wps-hide-login, two-factor, limit-login-attempts-reloaded, ithemes-security / better-wp-security, sucuri-scanner.
Step 3 — Try WP-CLI first (often the fastest path)¶
If WP-CLI is present, the whole recovery is two commands — deactivate the offender and create yourself an admin:
wp plugin deactivate wordfence wordfence-login-security wps-hide-login --allow-root
wp user create eidosadmin you@projecteidos.com --role=administrator --user_pass='STRONG-PASSWORD' --allow-root
Then skip to Step 7. If wp: command not found (common — most WP images don't ship WP-CLI), continue with the filesystem method below; it needs no extra tooling and no internet.
Step 4 — Force-deactivate the security plugin (filesystem, fully reversible)¶
WordPress auto-deactivates any plugin whose folder it cannot find. Renaming the folder is therefore a clean, reversible off-switch — it does not touch the database:
mv wp-content/plugins/wordfence wp-content/plugins/wordfence.off
# repeat for any other security/login plugin folder you identified
Then check for a firewall auto-prepend that some security plugins (Wordfence "Extended Protection") install in the web root:
wordfence-waf.phpis guarded — once the plugin folder is renamed it silently no-ops, so renaming the folder alone is safe and will not white-screen the site.- Only if the site front-end does white-screen after this: comment out the
auto_prepend_file = '.../wordfence-waf.php'line in.user.ini(or.htaccess/php.ini).
Step 5 — Inventory the admin accounts¶
You are in a PHP container, so use PHP directly (no WP-CLI or MySQL client needed). The file form avoids all shell-quoting trouble:
cat > /tmp/listadmins.php <<'PHP'
<?php
require '/var/www/html/wp-load.php';
foreach (get_users(array('role' => 'administrator')) as $u) {
echo $u->ID . ' | ' . $u->user_login . ' | ' . $u->user_email . ' | ' . $u->user_registered . "\n";
}
PHP
php /tmp/listadmins.php
Read the output:
- Your account is listed → the DB is intact; just reset its password (Step 6, option B) or create a fresh one (option A).
- Only third-party / unfamiliar accounts, or every
registereddate is today → the DB may have been replaced during a "fresh install"; create your own admin (option A) and treat the existing accounts with suspicion.
Step 6 — Create an owned admin (option A) or reset a password (option B)¶
Option A — create a new Eidos-owned administrator (preferred). Independent of any third-party account:
cat > /tmp/mkadmin.php <<'PHP'
<?php
require '/var/www/html/wp-load.php';
$login = 'eidosadmin'; // choose
$email = 'you@projecteidos.com'; // your email
$pass = 'ChangeThisToAStrongPassword!'; // choose a strong password
$uid = wp_insert_user(array(
'user_login' => $login,
'user_email' => $email,
'user_pass' => $pass,
'role' => 'administrator',
));
echo is_wp_error($uid) ? ('ERROR: ' . $uid->get_error_message() . "\n")
: ('Created administrator ' . $login . ' (ID ' . $uid . ")\n");
PHP
# edit the three values, then:
php /tmp/mkadmin.php
rm /tmp/mkadmin.php
Option B — reset an existing account's password (uses WP's own hashing):
php -r 'require "/var/www/html/wp-load.php"; $u = get_user_by("login", "ADMIN_LOGIN"); wp_set_password("STRONG-PASSWORD", $u->ID); echo "password reset for ".$u->user_login."\n";'
DB fallback (only if PHP CLI is missing): go to the database container's terminal and run
UPDATE wp_users SET user_pass = MD5('STRONG-PASSWORD') WHERE user_login = 'ADMIN_LOGIN';(WordPress accepts the legacy MD5 hash and rehashes to phpass on next login). Confirm the table prefix first withSHOW TABLES;— it may not bewp_.
Step 7 — Log in and verify¶
Go to https://<site>/wp-login.php and log in with the new credentials. With the security plugin disabled there should be no lockout, no 2FA prompt, and no breached-password rejection.
Step 8 — Re-enable security the right way (do not skip)¶
Leaving Wordfence off indefinitely is not the end state. Once you are safely in:
- Confirm your owned admin works and is not the one that gets locked out.
- Re-enable the plugin by renaming the folder back (
mv wordfence.off wordfence) only after you have, from insidewp-admin: - Allow-listed your own IP(s) in the firewall.
- Turned off the breached-password lockout (or briefed everyone to use unique strong passwords and a manager).
- Enrolled 2FA for the owned admin first, before enforcing it for all admins.
- Keep the
.offfolder until you have verified login survives a re-enable; it is your instant escape hatch.
Verification (post-recovery)¶
-
https://<site>/wp-login.phplogs in with the Eidos-owned admin account - The public site still renders correctly (front page + one content page)
-
wp-admindashboard loads with no PHP fatal / white screen - The owned admin account survives a security-plugin re-enable (Step 8) — i.e. it is allow-listed / 2FA-enrolled and is not locked out
- A full site backup has been taken and pushed off-host (see Post-incident)
- The admin + DB credentials are in Vault
Rollback / abort¶
Every action here is reversible:
- Re-enable a force-deactivated plugin:
mv wp-content/plugins/<plugin>.off wp-content/plugins/<plugin>. - A newly-created admin can be deleted from
wp-admin→ Users. - No content, theme, or database row outside
wp_users/wp_usermetais modified by this runbook.
If the public site white-screens at any point, the most likely cause is a dangling security-plugin auto-prepend (Step 4) — restore by either renaming the plugin folder back or commenting the auto_prepend_file line.
Post-incident¶
- Take a full backup and ship it off-host. The cleanest is the All-in-One WP Migration export (
.wpress) uploaded to thePECommonbucket (EIDOSDev1) undertneconnect.app/allin1_bkp/(or the equivalent prefix for the other sites). This is what was done on 2026-06-04 — see backups.md and the incident. - Store credentials in Vault. Admin login, DB /
wp-config.phpvalues, SFTP, plugin licence keys →kv_pe/tneconnect.app(see the per-app doc's "Credentials in Vault" table). - File the incident at
infra/incidents/YYYY-MM-DD-<site>-wordpress-lockout.md. - Ensure an Eidos-owned admin persists on every Dokploy WordPress site — that is the standing fix for KI-048.
Related¶
- KI-048 — the standing exposure (no owned admin; third-party dev controls the WP sites).
- KI-004 — Dokploy-hosted apps have no managed auto-update; plugin/site changes go in unsupervised.
- KI-038 — E2 has no block-volume backups; per-site exports like the
.wpressare the only off-host copy. - INC-2026-06-04 — the incident this runbook was written from.
- apps/13-tne-connect-wordpress.md, apps/11-pe-wordpress.md, apps/12-eidos-global-wordpress.md — the three sites this runbook covers.
- apps/18-dokploy.md — the platform hosting them.