WordPress Maintenance

Maintaining WordPress sites behind HTTP Basic auth — Playwright, urllib, and encrypted credentials

It’s pretty common to throw a layer of HTTP Basic auth on a WordPress site: a staging environment before launch, an internal test instance only employees should see, or any environment that wants an extra gate before the WordPress login screen itself. From a maintenance-tool point of view, this setup creates a peculiar “half-working, half-broken” asymmetry. The SSH/WP-CLI side runs fine. But everything HTTP-based — visual checks, thumbnail generation, browser-based fallback updates — hits 401 and dies. This post walks through how we resolved that asymmetry. What was breaking — two parallel paths, both blocked A maintenance tool actually touches a Basic-auth-protected site through two distinct paths: Playwright path: visual …

Read more
WordPress Maintenance

When paramikos defaults silently get your IP banned — the look_for_keys and allow_agent trap

One day a multi-site administrator reported a strange bug: “After running the app’s SSH connection test 2-3 times, my IP can’t reach SSH on that server for a long while.” The errors came back as Connection refused or Connection closed by …. The server wasn’t down, and SSH from a different IP worked fine. The source IP was being temporarily banned at the server. Two external investigation reports gave the cause: server-side protection mechanisms (fail2ban or PerSourcePenalties in OpenSSH 25+) detect short-windowed authentication failure spikes and temporarily ban the source IP. But the user had only clicked the test button 2-3 times — why were failures “spiking”? The answer turned …

Read more
WordPress Maintenance

When SSH commands hit a csh login shell — wrapping every command in /bin/sh -c across the codebase

One day a user reported an oddly asymmetric bug. In the “add new site” modal, picking an SSH profile and clicking “auto-detect WordPress install path” always failed with “no path found.” But clicking the WP-CLI path test button on the same SSH connection worked fine. Same credentials, same host — one succeeded, the other failed. Tracing it down, the culprit was an old foe: csh / bash incompatibility on the server side. This post walks through the fix, sweeping the same bug across the rest of the codebase, and the static-analysis test we added to keep it from coming back. The smoking gun — find: 2: unknown primary or operator …

Read more
WordPress Maintenance

Connection architectures for WordPress maintenance tools — mapping four products on a two-axis grid

While writing the comparison pages for ManageWP, MainWP, WP Umbrella, and InfiniteWP on our LP, I tried to line up the four products under a single “connection method” column — and got stuck. The same ManageWP gets called a “Hosted SaaS tool” in one source, a “Worker plugin tool” in another, and a “self-hosted” tool in yet another. On closer look, these labels are mixing two distinct axes into one column. Once you separate them, the four products fit cleanly into a two-axis, six-cell grid. This post lays out that grid and walks through what each cell means for day-to-day operations. Axis 1 — What gets installed on the client …

Read more
WordPress Maintenance

Playwright versus WordPress’s ‘admin email confirmation’ screen — how automation can clear the 6-month gate

If you drive the WordPress admin via Playwright for long enough, one day a screen you’ve never seen before will appear after login, and everything downstream stops working. Is admin@example.com still the correct admin email address? [ Yes, the email is correct ] [ Change the address ] That’s WordPress’s admin email confirmation screen. Roughly every six months, after the admin user logs in, this confirmation screen gets injected — standard behavior since WP 4.9. A human just clicks once. An automation script can’t see it without explicit handling. Why automation gets stuck A straightforward Playwright login looks like: page.fill(‘#user_login’, user) page.fill(‘#user_pass’, pwd) page.click(‘input[type="submit"]’) page.wait_for_load_state(‘domcontentloaded’) # Assumes we’re on the …

Read more
WordPress Maintenance

When WP admin shows a plugin update but WP-CLI doesn’t — making automation see proprietary updaters

You open the “Updates” page in WordPress admin and see that Elementor Pro / ACF Pro / vk-blocks-pro have updates available. Then you run wp plugin update –all from your automation, and those exact plugins don’t update. The asymmetry — “the admin sees it; WP-CLI doesn’t” — traces back to how WordPress detects updates and how premium plugins layer proprietary update mechanisms on top of that. Here’s the mechanism and how an automation tool can adapt. WordPress update detection is held by a transient cache WordPress doesn’t decide “is there an update?” on every request. It caches the answer in the wp_options table as a transient, valid for up to …

Read more
WordPress Maintenance

Solving ‘Permissions are too open’ from inside the app — auto-diagnosing and auto-fixing SSH key permissions

Almost every user new to SSH hits this wall: WARNING: UNPROTECTED PRIVATE KEY FILE! Permissions 0644 for ‘/Users/…/id_rsa.pem’ are too open. This private key will be ignored. They placed the key in ~/.ssh/, entered the path into the SSH settings, and clicked Connect — only to see this. The fix is a single command (chmod 600 ~/.ssh/id_rsa.pem), which is obvious to anyone familiar with SSH but the biggest stumbling block for users who don’t open a terminal. Here’s the design behind solving this inside the app — diagnose, confirm, then auto-fix — and how the phases broke out. Why OpenSSH demands 0600 OpenSSH (and paramiko, which mirrors the same check …

Read more
WordPress Maintenance

‘not a valid OPENSSH private key file’ — building a compat layer for seven SSH private-key formats

If you wire SSH into WordPress maintenance automation, you’ll meet this error sooner or later: SSHException: not a valid OPENSSH private key file “I configured the key file — why?” is the usual reaction. Tracing several real SSH-connection-test failures, the root issue becomes clear: paramiko alone can’t read SSH private keys outside the OpenSSH format. In production, hosting providers and key-generation tools produce different formats, and paramiko’s standard loader rejects many of them. Here’s the design of a “seven-format compat loader” we built to handle this. Far more SSH key formats than you’d guess “SSH key” usually conjures up —–BEGIN OPENSSH PRIVATE KEY—–, but in practice the keys you receive …

Read more
WordPress Maintenance

Renaming a site without losing its data — separating display name from a stable identifier

A client asks you to rename a site from acme-staging to the production name acme. The moment you rename it in the app, the DB backups, screenshots, and thumbnails you had been collecting all appear to disappear. The files are still on disk, but the new directory is empty. The data hasn’t carried over as “the same site.” It’s a trap you can fall into on day one, and we did — with our original design. Here’s how we redesigned things so renames don’t orphan data. Why the data appears to disappear — the site name was the key The original design of WP Maintenance Manager decided file locations based …

Read more
WordPress Maintenance

Beyond ‘Update All’ — selecting plugins across sites while keeping every safety mechanism on

“A vulnerability in Elementor was just disclosed. Several of the sites I maintain run Elementor. I need to update only Elementor across those sites today.“ If you maintain WordPress sites for multiple clients, this scenario happens several times a month. Core updates and other plugin updates can wait for the regular maintenance run, but a specific plugin needs to land urgently. The trouble is that mainstream maintenance tools don’t really offer a UI for “a targeted update across multiple sites, with safety mechanisms intact.” Here’s how that design problem can be solved. The limits of an industry-standard “Update All” Most WordPress maintenance tools have an “Update All” button on each …

Read more