When implementing a GCP load balancer for WordPress, we encounter a common issue: WordPress's default behavior of returning 301 redirects for custom URLs. The load balancer's health check requires a stable endpoint that consistently returns HTTP 200 status code to confirm instance availability.
Many developers first consider using /wp-admin/
as a health check endpoint. However, this approach has several drawbacks:
- Returns 302 redirect to login page when not authenticated
- Adds unnecessary load to admin interface
- Creates security concerns by exposing admin paths
The most reliable solution is to create a custom PHP file that bypasses WordPress's routing system:
<?php
// healthcheck.php in WordPress root directory
define('WP_USE_THEMES', false);
require_once('./wp-load.php');
// Simple check for WordPress core functionality
if (function_exists('wp_remote_get')) {
http_response_code(200);
echo 'OK';
exit;
}
http_response_code(503);
echo 'Service Unavailable';
For WordPress 4.7+, you can leverage the REST API:
add_action('rest_api_init', function () {
register_rest_route('health/v1', '/check', array(
'methods' => 'GET',
'callback' => function () {
return new WP_REST_Response('OK', 200);
},
'permission_callback' => '__return_true'
));
});
This creates an endpoint at /wp-json/health/v1/check
that always returns 200.
For maximum performance, configure Nginx to handle health checks directly:
location = /healthcheck {
access_log off;
return 200 'OK';
add_header Content-Type text/plain;
}
To ensure full stack health including database:
<?php
// db-healthcheck.php
define('WP_USE_THEMES', false);
require_once('./wp-load.php');
global $wpdb;
if ($wpdb->check_connection()) {
http_response_code(200);
echo 'DB Connected';
} else {
http_response_code(503);
echo 'DB Connection Failed';
}
When implementing health checks:
- Keep the endpoint lightweight - avoid loading themes or plugins
- Implement caching if checks become resource-intensive
- Consider adding basic system metrics (memory, disk space)
When configuring a GCP load balancer for WordPress, the health check mechanism requires an endpoint that consistently returns HTTP 200 status codes. However, WordPress's default behavior often returns 301 redirects, causing the health check to fail even when the site is operational.
WordPress has built-in URL canonicalization that automatically redirects non-canonical URLs to their "proper" versions. For example:
GET /index.php/newpage → 301 Moved Permanently Location: /newpage/
This behavior breaks load balancer health checks that expect a direct 200 response.
Here are three reliable solutions:
Method 1: Custom PHP Endpoint
Create a simple PHP file in your WordPress root directory:
<?php // healthcheck.php http_response_code(200); echo 'OK'; exit; ?>
This will always return HTTP 200 when accessed at /healthcheck.php
.
Method 2: Theme Functions.php Approach
Add this to your theme's functions.php
:
add_action('init', 'custom_health_check'); function custom_health_check() { if ($_SERVER['REQUEST_URI'] === '/healthcheck') { status_header(200); exit('OK'); } }
This creates a /healthcheck
endpoint that bypasses WordPress routing.
Method 3: REST API Endpoint
For WordPress 4.7+ with REST API:
add_action('rest_api_init', function() { register_rest_route('health/v1', '/check', array( 'methods' => 'GET', 'callback' => function() { return new WP_REST_Response('OK', 200); }, 'permission_callback' => '__return_true' )); });
Accessible at /wp-json/health/v1/check
.
To make the health check truly comprehensive (including database connectivity), modify the functions.php approach:
function custom_health_check() { if ($_SERVER['REQUEST_URI'] === '/healthcheck') { global $wpdb; $wpdb->get_results("SELECT 1"); if ($wpdb->last_error) { status_header(503); exit('Database Error'); } status_header(200); exit('OK'); } }
For better performance, you can handle the health check at the web server level:
# Nginx configuration location = /healthcheck { access_log off; return 200 'OK'; add_header Content-Type text/plain; }
Choose the method that best fits your infrastructure while considering the trade-offs between simplicity and thoroughness.