The migration issue of WordPress has always been a big problem for me.
Actually, it's not just for me. Although the migration process can be troublesome, it can be easily done by copying a directory and writing an SQL for the database (without changing the domain name or even writing anything). Now there are even ready-made plugins (such as Duplicator) that can handle it with just one click. What I'm worried about is Fēnglán (for a summary of the previous situation, see What are we talking about when we talk about Fēnglán's official website).
For Fēnglán, a more foolproof and one-click (although it may not be a good thing) solution is needed. As a long-time Docker user, I naturally thought of containerization. With Docker Compose, the website and database can be packaged in one directory, moved to a new machine without modification, and can be started or stopped with a single command.
In practice, I encountered many pitfalls (including those that I didn't have time to record before using Docker), so I will write them down here.
Steps#
The Compose file is from docker/awsome-compose:
services:
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10.6.4-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8.0.27
command: '--default-authentication-plugin=mysql_native_password'
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
expose:
- 3306
- 33060
wordpress:
image: wordpress:latest
volumes:
- wp_data:/var/www/html
ports:
- 80:80
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
volumes:
db_data:
wp_data:
In practice, I only moved the two mounted volumes, db_data
and wp_data
, to a local directory, and everything else remained basically unchanged.
This step will create two containers, one for the MariaDB database and one for the Nginx+WordPress web server. If the port mapped by wordpress
is not installed on the host machine, it can be set to 80
directly. I prefer to map it to another port and use reverse proxy (the new version of Baota can directly create reverse proxy projects, which is highly praisedwho is still using Baota in 2024), so I won't go into detail here.
After running docker compose up -d
, accessing the port or domain name will give you a brand new WordPress. If you need to migrate, you can use the aforementioned Duplicator to package and install it in the wp_data
directory.
Pitfalls#
Finally, it's time for my favorite part, the most torturous part of troubleshooting. Now it seems that most of the problems are not caused by containerization, but by some troublesome features of WordPress itself, which further strengthens my belief that although WordPress is good, it should still be abandoned.
Please note that I did not thoroughly investigate the root causes of the following problems. I only made simple speculations and searched for solutions. In my opinion, if you need to use such tricks to ensure usability in a modern environment, it is not worth wasting a lot of time on these things. It's good enough if it works.
ERR_TOO_MANY_REDIRECTS#
This problem occurred after I changed the WordPress address and site address in the settings to https://example.com
. There was no problem accessing the website itself, but when accessing the administration site, it would show ERR_TOO_MANY_REDIRECTS
. After multiple restarts and waiting in vain, I found a post on StackExchange here, and suddenly understood.
Native WordPress does not support setting HTTPS within the site, so I set up SSL in the Nginx reverse proxy. The WordPress address setting controls the Base URL for its redirects. So when accessing the site with HTTPS, the outer Nginx redirects me to the inner WordPress, and at this time, according to the settings, WordPress wants to redirect me to the HTTPS site, thus creating a loop of redirects.
My solution is similar to this post, but I know for sure that SSL is not set in the Nginx inside Docker, so I just changed the address back to starting with http
.
There are many ways to solve this problem. If you can access the database, you can modify the home
and siteurl
fields in the [sitename]_options
table. You can also add the following lines to the wp-config.php
file in the root directory:
define('WP_HOME','http://example.com');
define('WP_SITEURL','http://example.com');
After modifying the wp-config.php
file, the overridden items in the site settings will become gray and cannot be modified, which means that the values in the database are useless. Please pay attention to thisI was puzzled for a long time why I couldn't change them.
Plugin Installation and Directory Permissions#
For WordPress installed directly on the host machine, plugin installation is smooth and does not require any special operations. However, Docker images have a problem: the official WordPress image runs as the www-data
user, and the permissions of the copied/automatically created files are incorrect, which leads to the need to enter FTP credentials when installing plugins.
The solution is referenced from this issue and the gist mentioned in the reply. First, add the following line to the wp-config.php
file:
define('FS_METHOD', 'direct');
This will change the installation mode of plugins. Then, change the owner and permissions of the WordPress folder in the terminal:
docker exec -u root -it {CONTAINER_ID} /bin/bash
chown -R www-data wp-content
chmod -R 755 wp-content
Of course, instead of changing the owner, I directly changed the permissions of the folder to 777
. Don't follow my example, you will get scolded ( )I heard that Fēnglán's official website was taken down by hackers last time
Pros and Cons#
In my opinion, there are some advantages to migrating a legacy framework like WordPress to Docker:
-
Easy migration
This is my favorite advantage. The entire website is in one folder, so if you need to move, you don't need to back up and restore the database or change settings. Just compress the whole directory and take it with you.
-
Easy deployment
The entire system can be started with just one command:
docker compose up -d
. Shutting down and restarting is also a one-liner, and you can easily view the logs of both containers withdocker compose logs
. Although it is not recommended to put the database in a container in principle, containers are awesome! -
More secure (?)
In Docker Compose, the database and WordPress itself are all in a virtual network. Normally, the database is not exposed to the outside world, reducing the risk of being attacked. However, this point is questionable because as long as WordPress can access the database, the cost of directly exploiting existing vulnerabilities in WordPress is also very low.
Of course, there are also obvious disadvantages:
-
More complicated database and file access
After putting it into Docker, files and ports need to be mapped to access them, and some operations require entering the container. Database and file management have indeed become more complicated than before. Of course, you can also add a database management program like PHPMyAdmin to the Compose configuration (ready-made solution), but managing ports can be a bit tricky and I haven't successfully deployed it. You can try it yourself.
-
Need to deal with permission issues
As mentioned earlier, Docker means that inconsistencies in owners and permissions between inside and outside the container are more likely to occur, and solving them usually takes time (you may need to go back to the Dockerfile or enter the container).
-
Slower access speed
This is the most unacceptable disadvantage for me. WordPress is already notorious for its weak performance, and after entering Docker, every file access needs to go through directory mounting, and every database request needs to go through directory mounting as well. The perceived loading time of the website has even increased by more than 100%.
Conclusion and Outlook#
Overall, it was a relatively pleasant experience, but when I was tinkering with this, I found that the panel on my server suddenly couldn't read the Nginx configuration. Under the extremely slow access speed and the Nginx on the host machine crashing from time to time, I feel that I will turn to newer technology stacks. It's already 2024, why spend so much time tinkering with a blog framework that doesn't even natively support HTTPS (but the fact proves that WordPress is still necessary, as it is currently the most customizable and multi-author-friendly full-featured CMS in the community)? It's time to make a new choice!
Today I saw some new optimization methods (Redis, jsDelivr). If I have the energy later, I may try to tinker with them. After all, almost all of Fēnglán's posts are on WordPress, and it would be a pity to lose them.