The Problem
It all starts with a routine check of the shop’s sales figures one morning. The official WooCommerce management app can’t connect to the store! Opening the dashboard reveals that the WooPayments payment system has gone down — and digging further, the Jetpack plugin, the foundation the entire chain depends on, is disconnected! What happened? It’s not clear. We reconnect Jetpack manually and everything comes back online. Problem solved? No! Days later, completely out of the blue, it happens again! Always at night! The logs offer no useful clues. What now?
In the meantime, we built a useful plugin to monitor the Jetpack (and WooPayments) connection status, log the problem, and track disconnections over time.
We discover that all the alert emails arrive at exactly the same time: 4:13 AM!
The pattern was precise and baffling at the same time: the disconnection didn’t happen every night, but every 3-4 days, always in the same time window. Each morning the site came back online after a manual reconnect — a waste of time and, more importantly, a real risk for payment transactions during those overnight hours.
Before we could reach the root cause, we went down a long road full of false leads. It’s worth telling the whole story, because it faithfully mirrors how debugging works on complex systems.
How the Jetpack Connection Works (Briefly)
To understand the problem, a bit of context on how Jetpack manages its connection to WordPress.com is needed.
When Jetpack connects a site to WordPress.com, two distinct OAuth tokens are generated and stored in the database:
- Blog token (or site token): identifies the WordPress site as an entity. It is tied to the site URL.
- User token: identifies the administrator who authorized the connection.
Both tokens are registered on WordPress.com together with the site URL (siteurl) at the time of connection. Every subsequent call between the site and WordPress.com is signed using these tokens.
The critical point: if the site URL changes — even just by adding or removing www. — Jetpack detects what it calls an Identity Crisis. The site responds with a different URL than the one registered, the signature doesn’t match, and the connection is invalidated. From that moment on, WooPayments stops working, synchronization halts, and any service depending on Jetpack throws errors.
The Infrastructure
The site’s setup is relevant to understanding the vulnerability:
- HAProxy handles TLS termination and inbound load balancing
- Apache + mod_php serves WordPress
- All-in-One WP Migration Unlimited runs an automated nightly database backup
- The WordPress cron is managed via system cron (WP-CLI), not via native HTTP wp-cron
HAProxy hosts multiple sites on the same server, so routing is handled via the HTTP Host header. The key to the problem lies here: in certain edge cases, the Host header passed by HAProxy to the Apache backend could contain www.my-ecommerce.com instead of .my-ecommerce.com
The False Leads: A Debugging Chronicle
Attempt 1 — PHP Session Timeout
The first suspect was the PHP session cleanup. The system had session.gc_maxlifetime = 1440 (24 minutes), and the cleanup ran every 30 minutes at :09 and :39. The hypothesis: Jetpack’s OAuth token was being stored in a session and then wiped by the cleanup.
Verdict: innocent. Jetpack doesn’t use PHP sessions for tokens — it stores them in wp_options. We extended the timeout to 86,400 seconds anyway, but the disconnections continued.
Attempt 2 — e2scrub_all (Filesystem Check)
The system logs showed e2scrub_all running in the overnight window. The hypothesis: the filesystem check was locking I/O and causing connection timeouts.
Verdict: innocent. On VMs with virtual disks, e2scrub starts and exits immediately without doing anything. Dead end.
Attempt 3 — All-in-One WP Migration (First Reading)
The nightly AI1WM backup was scheduled at 02:00 UTC, exactly 13 minutes before our 04:13 alert (Italian time). The hypothesis: during the database export, the plugin was causing a race condition on Jetpack’s cron jobs.
This reading was partially correct: the plugin was involved, but not for the reason we thought. We developed an auto-recovery system for missing cron jobs — but it didn’t solve the real problem, which was the site connection being dropped, not just the cron jobs.
Verdict: involved, but not for the reason we thought.
The Turning Point: the URL Change
Looking more carefully at the plugin logs, we noticed that on the nights when disconnections occurred, the loss of the site connection (Jetpack site is not connected) appeared before the disappearance of the cron jobs. The order of events was reversed compared to our hypothesis: the cron jobs weren’t causing the disconnection — the disconnection was making the cron jobs disappear.
Searching through the plugins for anything that might modify siteurl and home in the database, we found the definitive culprit.
The Real Culprit: wp_guess_url()
In the All-in-One WP Migration Unlimited code, during the database reset/export process, we find this:
php
$guess_url = ( wp_guess_url() !== 'http:' ) ? wp_guess_url() : $backup['blog']['site_url'];
update_option( 'siteurl', $guess_url );
update_option( 'home', $guess_url );
wp_guess_url() is a WordPress function that tries to reconstruct the site URL from the current request context — reading $_SERVER['HTTP_HOST'], the script path, and other parameters.
The problem: during the execution of the nightly cron via WP-CLI, the HTTP context is not that of a normal browser request. The Host header that arrives depends on how the system cron invokes WP-CLI. If at that moment HAProxy had passed a request with www. in the Host header, my-ecommerce.comwp_guess_url() returned https://www. — and AI1WM wrote it directly into the database as the new my-ecommerce.comsiteurl and home.
Jetpack, on its next check, found the site URL changed from the one registered on WordPress.com: identity crisis, connection invalidated.
The reason it didn’t happen every night but every 3-4 days is now clear: it depended on which request HAProxy was handling at that precise moment, and whether that request carried the Host header with or without www. An intermittent event that was nearly impossible to reproduce on demand — which made debugging extremely frustrating.
The Definitive Fix
The solution is elegant in its simplicity. WordPress anticipates exactly this scenario: if WP_HOME and WP_SITEURL are defined as PHP constants in wp-config.php, any call to update_option('siteurl', ...) or update_option('home', ...) is completely ignored. Constants take absolute priority over database options.
php
// wp-config.php
// Force the correct hostname in all contexts (including WP-CLI)
$_SERVER['HTTP_HOST'] = $_SERVER['SERVER_NAME'] = 'my-ecommerce.com';
// HTTPS detection behind HAProxy
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
$_SERVER['HTTPS'] = 'on';
}
// WP-CLI needs the HTTPS context too
if ( defined( 'WP_CLI' ) && WP_CLI ) {
$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
$_SERVER['HTTPS'] = 'on';
}
// Lock site URL — immune to any update_option calls
define( 'WP_HOME', 'https://my-ecommerce.com' );
define( 'WP_SITEURL', 'https://my-ecommerce.com' );
This configuration acts on two levels:
- Hardcoded
$_SERVER['HTTP_HOST']: preventswp_guess_url()from generating a wrong URL in the first place WP_HOMEandWP_SITEURLas constants: even ifwp_guess_url()still returnedwww., the subsequentmy-ecommerce.comupdate_optioncall would have no effect on the database or WordPress behaviour
Since applying this change: zero disconnections.
The Plugin We Built: StSft Jetpack Connection Monitor
Throughout this long investigation we developed and progressively evolved a WordPress plugin that made the entire diagnosis possible: StSft Jetpack Connection Monitor.

What It Does
The plugin continuously monitors the status of Jetpack and related payment systems, and actively responds when problems are detected:
- Jetpack connection monitoring — checks both the site connection and the user connection, the two layers Jetpack requires to work correctly with WooPayments
- Payment gateway monitoring — WooPayments, PayPal, and any other configurable WooCommerce gateway
- Preventive cron job check — verifies that
jetpack_sync_cronandjetpack_sync_full_cronare present and scheduled - Auto-recovery — when cron jobs go missing, the plugin attempts to recreate them automatically using Jetpack’s native schedule; if needed, it falls back to WP-CLI
- Email alerts — immediate notification when a new issue is detected, plus a recovery email when everything is back online
- Day × Hour heatmap — a visual dashboard showing disconnection patterns over 7, 14, or 30 days, making systematic recurrences immediately visible
Why It’s Useful
On WooCommerce sites running WooPayments, a Jetpack disconnection means broken payments. Without active monitoring, the problem is discovered in the morning — after hours during which customers couldn’t complete purchases. The plugin reduces detection time to a few minutes and, for automatically resolvable issues, to zero manual intervention.
The heatmap in particular proved to be the key tool in this investigation: by visualising patterns across weeks, the cluster of events around 04:00 AM on non-consecutive nights was immediately readable, guiding the investigation in the right direction.
Download
The plugin is available free of charge. For information and download: info@stylesoft.it or visit the Jetpack-Woopayments Monitor plugin page.
Lessons Learned
1. The order of events in the logs is everything. The breakthrough came when we stopped looking for the cause of the missing cron jobs and instead looked at what happened before them. In complex systems, distinguishing cause from effect in the logs requires careful attention to the precise chronological order of events.
2. Intermittent bugs are the hardest. A bug that manifests every 3-4 days, dependent on an interaction between the system cron, HAProxy, and a backup plugin, cannot be reproduced on demand. The only way to diagnose it is to collect data patiently over time — hence the value of having a dedicated logging system.
3. WordPress constants always override options. WP_HOME and WP_SITEURL as constants in wp-config.php are the correct defence against any attempt — intentional or accidental — to change the site URL. If your site runs behind a reverse proxy, defining them explicitly is a best practice.
4. Backup plugins touch the database at a very deep level. All-in-One WP Migration is an excellent product, but like any backup/migration plugin it operates at a very low level of the database. It’s worth examining what it writes during an export, especially on sites with non-standard network configurations.
How We Fixed It — The Practical Version
This section is for anyone who wants to apply the fix without necessarily following all the technical reasoning.
If Jetpack disconnects periodically on your site, especially on sites behind HAProxy or other reverse proxies, try this change to wp-config.php:
Add these lines before the /* That's all, stop editing! */ comment, replacing yoursite.com with your actual domain:
php
define( 'WP_HOME', 'https://yoursite.com' );
define( 'WP_SITEURL', 'https://yoursite.com' );
These two lines prevent any plugin — including backup and migration plugins — from modifying the site URL in the database. Jetpack will never see a different URL from the one it registered with, and Identity Crisis disconnections cannot occur.
If you also have a reverse proxy (HAProxy, Nginx, Cloudflare) and use WP-CLI, add this too, before the constants:
php
$_SERVER['HTTP_HOST'] = $_SERVER['SERVER_NAME'] = 'yoursite.com';
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) &&
$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
$_SERVER['HTTPS'] = 'on';
}
That’s it. No extra plugins, no complex changes — two lines of configuration that permanently close the issue.
Experiencing a similar problem, or considering the StSft Jetpack Connection Monitor plugin for your site? Write to us at info@stylesoft.it — we’re always happy to help.
