Disaster Recovery 101: Architecting Auto-Failovers for MongoDB and WordPress Deployments on Linode
Establishing a Robust MongoDB Replica Set for High Availability
Achieving true disaster recovery for a WordPress site hinges on the resilience of its data layer. For MongoDB, this means architecting a replica set that can withstand node failures and automatically elect a new primary. We’ll focus on a three-node replica set, a common and effective configuration for production environments, deployed on Linode instances.
First, ensure your Linode instances have static IP addresses. This is crucial for consistent communication within the replica set. Let’s assume we have three Linode instances with IPs: `192.168.1.10` (node1), `192.168.1.11` (node2), and `192.168.1.12` (node3).
MongoDB Installation and Configuration
On each Linode instance, install MongoDB. The exact commands may vary slightly based on your Linux distribution, but for Ubuntu/Debian:
sudo apt update sudo apt install -y mongodb sudo systemctl enable mongod sudo systemctl start mongod
Next, we need to configure MongoDB to allow replica set communication. Edit the MongoDB configuration file, typically located at `/etc/mongod.conf`. We need to set the `replication.replSetName` and ensure `net.bindIp` is set to `0.0.0.0` or the specific private IP of the Linode instance to allow connections from other nodes. For simplicity and assuming a private network, `0.0.0.0` is often used, but in a more secure setup, bind to the private IP.
# /etc/mongod.conf
storage:
dbPath: /var/lib/mongodb
journal:
enabled: true
systemLog:
destination: file
path: /var/log/mongodb/mongod.log
logAppend: true
net:
bindIp: 0.0.0.0 # Or the specific private IP of the Linode
port: 27017
security:
authorization: enabled # Recommended for production
replication:
replSetName: "rs0" # Name of our replica set
processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongod.pid
After modifying the configuration file on all three nodes, restart the MongoDB service:
sudo systemctl restart mongod
Initializing the Replica Set
Connect to the MongoDB instance on one of the nodes (e.g., node1) using the `mongo` shell. If you enabled authorization, you’ll need to authenticate first. For this example, we’ll assume authorization is not yet fully configured for simplicity during initialization, but it’s critical for production.
mongo
Once in the `mongo` shell, initiate the replica set configuration. Replace the IP addresses with your actual Linode private IPs.
rs.initiate(
{
_id : "rs0",
members: [
{ _id: 0, host: "192.168.1.10:27017" },
{ _id: 1, host: "192.168.1.11:27017" },
{ _id: 2, host: "192.168.1.12:27017" }
]
}
)
You should see output indicating the replica set has been initiated. You can verify the status by running `rs.status()` in the `mongo` shell. All members should eventually reach an `PRIMARY` or `SECONDARY` state. It might take a moment for the election process to complete and for secondaries to sync.
Architecting WordPress for MongoDB High Availability
WordPress, by default, relies on MySQL. To leverage our MongoDB replica set, we need a WordPress plugin that supports MongoDB as a database backend. The most prominent and actively maintained option is the “MongoDB for WordPress” plugin.
Plugin Installation and Configuration
Install the “MongoDB for WordPress” plugin through the WordPress admin dashboard. Once activated, navigate to its settings page. Here, you’ll configure the connection string to your MongoDB replica set.
The connection string format for a replica set is:
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
For our setup, assuming no authentication for now (again, not recommended for production), the connection string would look like this:
mongodb://192.168.1.10:27017,192.168.1.11:27017,192.168.1.12:27017/wordpress_db?replicaSet=rs0
Crucially, the `replicaSet=rs0` parameter tells the driver to connect to a replica set named `rs0`. The driver will automatically discover the current primary and connect to it. If the primary fails, the driver will detect the disconnection and attempt to connect to another available member, which will then be elected as the new primary.
WordPress Application Server Configuration
Your WordPress application servers (e.g., running PHP-FPM with Nginx or Apache) need to be able to reach the MongoDB replica set nodes over the network. Ensure your Linode firewall rules allow traffic on port `27017` from your WordPress web servers to your MongoDB servers.
The MongoDB PHP driver must also be installed on your web servers. You can typically install it using PECL:
sudo pecl install mongodb echo "extension=mongodb.so" | sudo tee /etc/php/7.4/mods-available/mongodb.ini # Adjust PHP version as needed
After installing the extension, restart your web server’s PHP process manager (e.g., PHP-FPM) and the web server itself.
Implementing Automated Failover for WordPress Web Servers
While MongoDB handles its own data layer failover, the WordPress application servers themselves are a single point of failure. To achieve true high availability, we need to deploy WordPress across multiple Linode instances and use a load balancer.
Load Balancer Setup (HAProxy)
HAProxy is an excellent choice for load balancing HTTP traffic. We’ll set up HAProxy on a dedicated Linode instance or as a service managed by Linode’s NodeBalancers.
Here’s a basic HAProxy configuration for balancing traffic across two WordPress web servers (`192.168.1.20` and `192.168.1.21`):
# /etc/haproxy/haproxy.cfg
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend http_frontend
bind *:80
acl is_static url_beg /wp-content/uploads/
use_backend static_backend if is_static
default_backend wordpress_backend
backend wordpress_backend
balance roundrobin
option httpchk GET / HTTP/1.1\r\nHost:\ yourdomain.com
http-check expect status 200
server wp1 192.168.1.20:80 check
server wp2 192.168.1.21:80 check
backend static_backend
# For serving static assets directly from a dedicated server or CDN
# For simplicity, we'll just pass it through to the wordpress backend for now
# In a real-world scenario, you'd point this to a CDN or static file server.
balance roundrobin
server wp1 192.168.1.20:80 check
server wp2 192.168.1.21:80 check
Install HAProxy:
sudo apt update sudo apt install -y haproxy sudo systemctl enable haproxy sudo systemctl start haproxy
After configuring HAProxy, restart the service:
sudo systemctl restart haproxy
WordPress Server Health Checks
HAProxy’s `check` directive performs basic TCP-level health checks. For a more robust setup, you can implement an HTTP health check endpoint on your WordPress servers. This could be a simple PHP file that returns a `200 OK` status if WordPress and its database connection are healthy.
Create a file like `/var/www/html/healthcheck.php` on each WordPress server:
<?php
// /var/www/html/healthcheck.php
header('Content-Type: application/json');
// Basic check for MongoDB connection (requires MongoDB PHP driver)
$mongo_connection_ok = false;
try {
// Replace with your actual MongoDB connection string
$mongo_uri = "mongodb://192.168.1.10:27017,192.168.1.11:27017,192.168.1.12:27017/wordpress_db?replicaSet=rs0";
$client = new MongoDB\Client($mongo_uri);
$client->selectDatabase('admin')->command(['ping' => 1]); // Simple ping to check connection
$mongo_connection_ok = true;
} catch (Exception $e) {
// Log the error for debugging
error_log("MongoDB Health Check Failed: " . $e->getMessage());
}
if ($mongo_connection_ok) {
http_response_code(200);
echo json_encode(['status' => 'ok', 'message' => 'WordPress and MongoDB are healthy.']);
} else {
http_response_code(503);
echo json_encode(['status' => 'error', 'message' => 'MongoDB connection failed.']);
}
?>
Update your HAProxy configuration to use this health check:
backend wordpress_backend
balance roundrobin
# Use the healthcheck endpoint
option httpchk GET /healthcheck.php
http-check expect status 200
server wp1 192.168.1.20:80 check port 80
server wp2 192.168.1.21:80 check port 80
Restart HAProxy after these changes.
Testing and Verification
To test the auto-failover:
- MongoDB Failover: Stop the `mongod` service on the current primary MongoDB node. Observe the `rs.status()` output on one of the secondary nodes. Within a minute, a new primary should be elected. WordPress should remain accessible, though there might be a brief interruption during the election.
- WordPress Server Failover: Stop the web server (Nginx/Apache) or PHP-FPM on one of the WordPress application servers. HAProxy should detect the failure via its health checks and stop sending traffic to that server. WordPress should continue to be served by the remaining active server.
Regularly test these failover scenarios to ensure your architecture is robust and your team is familiar with the recovery procedures.