Preface
The idea came about because the last time I changed the domain name of my image hosting service, and then batch-modified the image hosting URLs in the WordPress database, a formatting issue occurred during the copy-pasting of the SQL commands, causing the WordPress database in MariaDB to crash. Although I managed to restore it later by logging into WordPress and using the backup previously made with the ”WPvivid Backup Plugin”, the blog was down for about 30 minutes in the process... This was only because I was lucky enough to still be able to log into WordPress at the time; if I hadn't been able to log in, it would have taken much longer to fix. I feel that regularly using mysqldump to back up the MariaDB database is indeed necessary, so I'll put it on the schedule (since the source site is hosted on a Mac mini, and previously I didn't really want to run scripts on the Mac mini).
After considering it for a while, I feel the most secure way is to set up a redundant WordPress site (which can be deployed in the same home data center, on a cloud host, or in a friend's home data center in the same or a different city), and then use a backup plugin (such as the WPvivid Backup Plugin) to regularly back up WordPress and database data to the redundant site. When needed, the latest backup data from the source site can be imported immediately to provide services. Combined with the hot standby origin site feature of a CDN, this can achieve: local/remote disaster recovery, and hybrid local and cloud deployment disaster recovery.
Create and initialize the MariaDB database (optional)
WordPress needs to use a MariaDB database (MySQL is also fine, but given a choice, MariaDB is always preferred). Since I prefer to use the docker run method to deploy WordPress (deploying WordPress via docker-compose does not require creating MariaDB separately), I need to manually create the MariaDB database and perform the initial configuration (if you have an existing MariaDB, just initialize it directly). The recommended process for creating a new MariaDB database is as follows:
Create a new public-net bridge (optional)
docker network create public-net
**Item 9:**
This step is not mandatory, but because both the MariaDB container and the WordPress container need to reference the non-default bridge `public-net` so that WordPress can directly access MariaDB using the container name, it needs to be created in advance (if you have other existing non-default bridges, they can also be reused).
Actually, using the `--link` parameter in WordPress to directly link to MariaDB can achieve the same purpose. However, for easier management and operations in the future when there are more containers (for example, creating different bridges to connect containers in different zones), try to avoid using the `--link` parameter. With too many containers, linking them everywhere might get confusing and make operations difficult, so it is best to develop a good habit of using the `--net` parameter from the very beginning.
Create a new MariaDB database (optional)
If there is no MariaDB database container in the environment or you do not want to reuse an existing one, you need to create a new one.
Create the directory on the host machine that needs to be mounted into the MariaDB container
mkdir -p /docker/mariadb/db
Create the MariaDB container
The command to set up the MariaDB database in `docker run` format is as follows:
docker run --name=mariadb01 -d --restart=always --net=public-net \
-p 3306:3306 \ #映射宿主机的3306端口到容器的3306端口
-v /docker/mariadb/db:/var/lib/mysql \ # 挂载前面创建的宿主机目录到容器内部指定目录
-e MARIADB_ROOT_PASSWORD=123 \ #指定数据库root用户对应的密码,这个大家自行修改
mariadb:10.11
Initialize MariaDB database
For details, please refer to my other article:Tips and Tricks Series: Creating a New Empty Database and Granting Permissions to Corresponding Users, in the following text, it is assumed that the database name, corresponding username, and password after initialization are all wordpress.
Deploy WordPress and initialize
Deploy WordPress using the docker run method
Create the directory on the host machine that needs to be mounted into the WordPress container:
mkdir -p /docker/wordpress/html
The command to set up WordPress in docker run format is as follows:
docker run --name=wordpress -d --restart=always --net=public-net \
-p 8080:80 \ #映射宿主机8080端口到容器的80端口,请大家根据实际环境选择宿主机端口
-v /docker/wordpress/html:/var/www/html \ #映射宿主机上创建的目录到容器内指定路径
wordpress
Note: Please delete the comments after # yourself
Deploy WordPress using the docker-compose method
For those who do not want to create and initialize the database separately, you can directly use the docker-compose method to deploy WordPress by following these steps:
Create the directory on the host machine that needs to be mounted into the WordPress container:
mkdir -p /docker/wordpress
Create docker-compose.yml:
vim /docker/wordpress/docker-compose.yml
Then paste the following content into docker-compose.yml and save it:
version: '3.0'
services:
db:
image: mariadb:10.11
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: 123 # 按需修改
MARIADB_DATABASE: wordpress
MARIADB_USER: wordpress
MARIADB_PASSWORD: wordpress # 按需修改
volumes:
- './db:/var/lib/mysql'
networks:
- default
app:
image: wordpress:latest
restart: unless-stopped
ports:
- 8080:80 # 按需修改。与防火墙开放端口一致。
environment:
WORDPRESS_DB_HOST: db # 如果需要使用命名容器,使用 'mariadb-wp'
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress # 按需修改
volumes:
- './app:/var/www/html'
depends_on:
- db
networks:
- default
redis:
image: redis:alpine
restart: unless-stopped
volumes:
- ./redis-data:/data
networks:
- default
networks:
default:
name: public-net
services:
cd /docker/wordpress
docker-compose up -d
Initialize WordPress
Usehttp://宿主机IP:8080image: mariadb:10.11

restart: unless-stopped

environment:

MARIADB_ROOT_PASSWORD: 123 # Modify as needed

MARIADB_DATABASE: wordpress

MARIADB_USER: wordpress


MARIADB_PASSWORD: wordpress # Modify as needed
volumes:Docker Series: Building Your Own Reverse Proxy Based on NPM Using Docker和Linux Panel Series: Configuring Reverse Proxy and Publishing Using Non-443 Ports。
Install and enable the WPvivid backup plugin
- ”./db:/var/lib/mysql”

networks:
- defaultapp:
image: wordpress:latest

restart: unless-stopped

ports:
Install FTP server software on the target site (optional)
- 8080:80 # Modify as needed. Consistent with the open port of the firewall.

environment:
The method of installing ftp software on the target site is highly dependent on the target site's operating system environment. My target system is a Debian 12 virtual machine with BT Linux Panel installed, so I will use my environment as an example to demonstrate the ftp installation. Please research other environments on your own; it's just about installing an ftp server anyway.
Search for and install ”Pure-Ftpd” in the ”App Store” of the BT Panel:

Then click ”Add FTP” under ”FTP” to add the ftp user and home directory on the target site:

The key lies in the user's root directory path in the red box:

The path is:
/docker/wordpress/html/wp-content
Why is the path the one above? Actually, it can be seen in the WPvivid configuration interface:

Because when adding remote storage via ftp in WPvivid later, you cannot directly use ”/” to specify the root location. Therefore, the FTP user's root directory is pointed to /wp-content here, making it convenient to specify the root directory using /wpvividbackups when adding it later.
After successfully adding the FTP user, please confirm whether the root path is correct:

To connect to the target site using ftp passive mode, the pure ftp configuration needs to be modified as follows:

PassivePortRange:
Defines the port range that the ftp server tells the source site's ftp client to connect to when establishing a data connection in passive mode (please modify according to your actual situation). Since this needs to be configured on the target site's firewall (if enabled), the complicated part here is that if the target site is hosted on a cloud server, these ports must be allowed in both the cloud provider's security policy and the cloud server's own security policy. For example, if using a cloud server on Tencent Cloud, you first need to:

Then allow access to these ports in the ufw firewall of the cloud server's Debian system itself.
ForcePassiveIP:
This is very important. If it is the same intranet environment, you need to specify the intranet IP address of the target site's WordPress host machine; if it is a cloud server, you can directly use the public IP.
After completing the configuration, you can use an ftp client in passive mode to access and confirm whether the ftp server on the target host is running normally.
**Item 9:**
Active and passive modes of ftp are actually quite interesting. Once you understand them, many network failures will make sense. I suggest you study them if you are interested. Everyone's ftp environment might be different, so if problems arise, you may need to analyze the causes yourself. If all else fails, you will have to use other methods.
In addition, if combined with the IP address provided by virtual LAN software like Tailscale, you can form disaster recovery and hot standby solutions with hosts in the same city, different locations, or even anywhere in the world.
WPvivid configuration on the source site
Add remote storage
Fill in the information according to the relevant configuration of the target site's ftp in the previous section:

The path is not the absolute path of the target site's host machine, but the relative path to the root directory set for the ftp user. This is very important; I struggled with this for a long time~.
If the connection is successful, it will be displayed under the storage options below:

Schedule backups
Select the backup frequency and backup content in the schedule tab according to your actual needs, then select ”Send Backups to Remote Storage”, and then select ”Save Changes” in the red box in the lower-left corner:

By default, scheduled backups will upload the backup data of the source site to the target site and then delete the local backup. If you want to keep the backups generated by scheduled tasks on the source site as well, you need to check the option in the red box under the settings tab:

Note: This method has many limitations. Although it works, it is no longer the recommended method. The reasons and alternative methods will be discussed in the last section.
If you want to configure manually outside the scheduled time, you can do so under the ”Backup & Restore” tab:

You can perform a backup here first to make it easier to view on the target site.
WPvivid configuration on the target site
Actually, the target site does not need any configuration. You only need to click ”Scan Uploaded Backups or Received Backups” in the red box under the Backup & Restore tab, and then select and click restore from the backups that appear below. Since we performed a backup on the source site above, clicking the ”Scan Uploaded Backups or Received Backups” button in the red box below should normally show the backup data of the source site above:

Summary
In fact, the key to this method is that the source site directly uploads the backup files to the directory where the WPvivid plugin stores backups on the target site via ftp. In this way, the target site only needs to scan to immediately see the configuration files of the source site and restore them in time. Even if the WordPress on the source site cannot be opened at all, access to WordPress can be restored in a very short time. However, even if you do not use ftp but other remote storage methods, it is just one more step of downloading and then manually transferring to the target site. It doesn't actually take much more time, but from a technical perspective, it is not as elegant as this ftp method.
In addition, after the slave site is also published through a reverse proxy, you can point the hot standby source site to this slave site on the CDN, thereby achieving disaster recovery for the WordPress site. Of course, in this case, it is best to deploy the slave site on a cloud server or in a different location. Since I deploy them all in my home data center, they will all go down together if there is a power outage...
After using it for a while, the method of using FTP for remote backup has been phased out for two reasons:
Only one remote node can be set up
In addition to a hot standby WordPress site in my intranet, I now also have a mirror site on a Tencent Cloud server, and there might be more in the future. Backing up to just one remote node is not enough.
Verification is required during restoration
For configurations backed up using this FTP method, when I restored them on the remote site, it actually asked me to enter the FTP server information (IP, port, username, and password), which is quite annoying.
So although the idea is still the same, I changed the implementation method. Instead of directly sending the regularly backed up configurations to the remote slave site via ftp, I changed it to use Syncthing's multi-point folder synchronization method.
Change the regularly backed up files of the main site's WPvivid from ”Send Backups to Remote Storage” to ”Save Backups to Local”:

Then use Syncthing to directly sync the regularly backed up files in the local WPvivid directory to the same directory of the WPvivid plugin on other sites. This method is very perfect. For the detailed Syncthing configuration method, please refer to my other article:Docker Series: Detailed Tutorial on Implementing Multi-Point Folder Synchronization Based on Syncthing Using Docker。