Migrating WordPress.com to Docker Containers

  1. Did you ever want to keep a copy of your WordPress.com in your own site?
  2. Did you want a copy of your WordPress site, just so you can customize it for your own purposes?
  3. Do you have a little experience with Docker containers?
YouTube player

I have a shell script to automate the process for you, uploaded into Github:
https://github.com/studio-1b/containerize_wordpress_com

And below, I will explain how it works. And the caveats.

WARNING: This post can also be categorized as Fantastic Failures post. So far, I have identified:

  1. The import process sometimes does not complete, skipping failures. Often I’ve seen this as missing feature images, when attachment posts are not imported. The workaround, seems to be to run the import process on the WXL xml file multiple times, until you no longer get errors. The problem with this, is even though the logic prevents posts from begin duplicated, menu entries are duplicated with each import attempt. However the latter problem is easier to fix, within the WordPress admin, of the new copy of your site.
  2. The Theme doesn’t download. But this was a known limitation. You have to install it manually, again, in the admin login, in the new copy of your site.
  3. The menus and categories were copied correctly.
    1. But menus are only appearance items copied over. Widgets, header, and footers are not copied.
  4. [googlemaps ] shortcode doesn’t work. So the shortcode isn’t built into WordPress software in Linux. I’ve created a wordpress plugin that will duplicate it. The script will install it.
  5. [gallery ids=”9642,9577″ type=”rectangular”] shortcode functionality is different in WordPress.com versus WordPress software in Linux. The shortcodes transfer over to WordPress software correctly as shortcodes in the post content, but:
    1. WordPress.com functionality: clicking on image, doesn’t bring enlargement of image, in slideshow mode w other gallery images, in same page.
    2. WordPress software: clicking on image, opens image in its own page, BUT…
      1. those links may or may not have imported correctly. If it isn’t imported correctly as attachment page for image, then the link is broken. And when you click on it, instead of getting the full image, it gives you message that link is broken.
    3. The most minor issue, is that the gallery images are in thumbnail sized, not medium sized. And that they are not formatted in a justified format.

    The same plugin mentioned before that emulates [googlemaps ], will also override the [gallery] shortcode behavior in the Linux WordPress, so it more closely matches wordpress.com’s image gallery.

  6. Newer posts in WordPress.com, have an object called a gallery block (instead of inserting a [gallery] shortcode). Which will export correctly to recent versions of WordPress. BUT the gallery block is NOT clickable in WordPress software in Linux (no enlargement), while the gallery block in wordpress.com emulates [gallery] almost completely, except for justified formatting. The gallery override plugin, also overrides the behavior of gallery blocks, so it more closely (but not exactly) matches the behavior or wordpress.com image galleries.
  7. WordPress needs to know the host, it is serving from. This means the site url and home url configuration, has to match the host. Sometimes, this even means changing the port from the default 80, to another port. This is done in the script automatically, assigning the first available port after 8888.
    https://www.serverlab.ca/tutorials/linux/web-servers-linux/how-to-change-port-80-to-8080-for-wordpress/

Until these issues are resolved, you can’t create a seamless backup site on your own hardware, with the method outlined here. Nor do I have a solution for starting a site on your own hardware, and uploading it to wordpress.com. I can’t even find a list of functionality differences on the internet. However, I have tried to address these issues, as simply as I can. Hopefully, it can give a clue, on how to address them more completely.

What this will do
1.Create a container with WordPress, using latest container images uploaded to Docker’s repositories.
2.Download your posts from WordPress.com
3.Download your images and media from wordpress.com
4.It will install the default “twenty twenty four” theme.
5.You can browse most of your content in posts, and the images will be there.
6.You will see what you’re dealing with, what you are missing, if you choose to manually do this migration yourself, rather than buy someone’s migration software. And I haven’t even reviewed any, so I can’t say you will get 100% functionality that you got from WordPress.com. But WordPress.com is a slow-moving target to match, so maybe someone has built a migration software, to keep up with features you use in their hosted site.
7. You can make changes to this container copy, without it ever affecting the wordpress.com content and site. (As far as I know, b/c downloading exports from the original site, doesn’t modify the site itself).

Is this the solution you are looking for? B/c there are 3 possible solutions, I think you might want to accomplish:

WordPress.com posts and media to Docker Container


(This is procedure this post is outlining below)
WordPress posts and media to Docker Container.


You typically do this to migrate your Linux WordPress content, data, and media (not from WordPress.com) to upgraded more recent version of software.

The data is stored in a agonistic way, that can be re-imported by another version. Some design and appearance elements need to be manually re-applied.

WordPress whole installation to Docker Container.


You would typically do this to backup and restore of your Linux WordPress (not from WordPress.com), into containerized format. Everything is the same, such as WordPress version, php version, and mysql version.

It is just deployed as container image. The advantages, is that containers is more or less portable (mostly, not between different processors families), b/c the software believes it is always running in a time capsule in the same platform, hardware, and operating system.

There maybe migration plugins to do this for you. But I did it by hand. So I am going to tell you how to do it, if you choose to do it manually. I suggest you have someone with technical experience, who understands these instructions.

So let’s try export WordPress into Docker (what we can).

What you should have:

  • Existing WordPress.com site
  • in WordPress.com managed hosting
  • Planned WordPress installation on linux hosting
    • Docker host, on the same above linux host

Why doesn’t WordPress export support site design

Some elements of the site design, such as the current stylesheet, and current theme, is in the wp_options table in MySql. Even though some customizations are stored in wp_content folder in file system, they aren’t activated unless the wp_options table has the setting saved to activate it, and otherwise contains the default values.

Short answer is, default WordPress export does not export the wp_options table.

Issues:

  • WordPress.com only has 1)export media and 2)export posts and content. This means, your site design and any plugins will not get exported. All we can do, is recreate another wordpress site, recreate the design, and re-integrate plugins, after we have imported all your posts and media. And we would do this in Docker Containers here.
  • WordPress installation on Linux hosting. If you have access to the MySQL database that the post content is stored AND the PHP source code that WordPress installation is comprised of, you can simply transfer everything to a container, with plugins and all. The caveat here, is you have to search for the versions of WordPress, PHP and MySQL, that your installation is running on, and recreate those software packages. The early versions of wordpress like mine, seem esp sensitive to this.

    PS: We will show you how to upload your WordPress installation, to a PRIVATE docker repository. It has to be private, b/c WordPress installation has many passwords that need to be kept secret.

    How to execute it:

    ./containerize_wordpress_com.sh [wordpress url] [wordpress username]
    

    When the above command is run on the Linux computer that has Docker hosting installed, the script takes the url, and tries to login to your wordpress account. It does this with the username you provided. It also needs your password, but you should have a file named with your [wordpress username] and inside is the password.

    Once the script is logged in (by copying the cookies after logging in), it tries to get exports for the media(.tar file) and content(.xml). After both are downloaded, the script then proceeds to start the containers for the copy of your site.

    The script downloads the latest wordpress and mysql containers, and starts them. It assumes that the latest versions of wordpress and mysql images, are compatible. This is usually the case.

    After the wordpress container is started, the script installs utliity called wp-cli, and uses this to create a new empty default site of wordpress, with a initial user named “admin”. The admin password is created randomly and put in the “admin” file. This “admin” user, is who you will login with, initially, into the new copy of wordpress. The script looks for first open port after 8888, and assigns it to your new wordpress container.

    Up to now, both wordpress and mysql have no data, and just the basic software. Then the script copies to tar file into wordpress container, and unarchives it into the wp-contents directory in wordpress PHP container.

    After this is done, then it then installs the plugin that enables gallery] shortcode and googlemap] shortcode to work similarly as the way it did, on wordpress.com. Only half of your content from your wordpress.com site, are on the new containers, only on the PHP container.

    Then the script will start the WXL xml import process on the wordpress PHP container. This process takes a very long time, more than 4 hours. This is certainly a bug, but I don’t want to fix their bug. This copies your post text, from the WordPress container, to the mysql container. My script assumes it works the first time, every time. If not, you may have to execute

    docker exec -w /var/www/html/ $CONTAINER_NAME  wp import /tmp/$WXL_FILE --authors=create --allow-root
    

    several times, until you don’t get anymore errors. replace $CONTAINER_NAME with name of the wordpress php container and $WXL_FILE with the .xml export.

    If you ran the command, with arguments for container image repositories, like:

    ./containerize_wordpress_com.sh [wordpress url] [wordpress username] [aws ECR php repository url] [aws ECR sql repository url]
    

    Then the [aws ECR php repository url] and [aws ECR sql repository url] look like:

    ./containerize_wordpress_com.sh https://mysite.wordpress.com bob@gmail.com 99999.dkr.ecr.region.amazonaws.com/mysite-php-repo:tag 99999.dkr.ecr.region.amazonaws.com/mysite-sql-repo:tag 
    

    This variation of the command, will try to upload the latest built container image with all your content presumably after the import process has finished, to AWS ECR container image repositories. And you should already have created ECR private repos named “mysite-php-repo” and “mysite-sql-repo”. Your account number should match the 99999, region replaced with your own, and tag is usually going to be “latest”. It will then create images with your imported wordpress content in both containers, then upload them into the respective container image repository, with a :latest tag AND a tag with today’s date. Each image is basically uploaded with 2 names, and the “latest” name is taken by every new image uploaded. And it keeps it’s 2nd name (the date) assigned uniquely for itself. This step allows you to download the images, and start the containers on any docker host, afterward.

    Container running your WordPress should be running now. Just goto your browser, and type http://[docker host ip]:[assigned port]. You are all done. What comes after this paragraph is additional details, that may be interesting about this process.

    ———————-

    Explanation of “containerize_wordpress_com.sh”

    Everything the script does, you can realistically do manually, by commands. But I’ll explain the script below. The explanation is highlighted in yellow

    Check that the command wasn’t just executed to browse the command.

    WP_URL=$1
    if [ "$WP_URL" == "" ]; then show user helper message for empty command, then exit with error 1
      ...removed ordinary code...
      exit 1
    fi
    

    Explore if user provided input indicating he has wordpress files already, or if this script should download the exports from URL.

    if [ "${WP_URL:0:8}" == "https://" ]; then check if provided URL is secure
      curl $WP_URL &> /dev/null check if provided URL is connectable
      if [ $? -ne 0 ]; then  exit with error 2, if previous command failed
        ... exit 2
      fi
      curl $WP_URL/wp-login.php &> /dev/null  check if provided URL has login ability
      if [ $? -ne 0 ]; then  exit with error 2, if previous command failed
        ... exit 2
      fi
    else
      expected filenames, have .tar and .xml at end, and are named the same as the argument
      FILENAME=${WP_URL%.*}
      TAR_FILE=$FILENAME.tar
      WXL_FILE=$FILENAME.xml
    
      if [ ! -f $TAR_FILE ]; then  exit w error 3, if TAR file does not exist
        ... exit 3
      fi
      
      if [ ! -f $WXL_FILE ]; then exit w error 3, if WXL file does not exist
        ... exit 3
      fi
      IS_WXL_AND_TAR_EXISTS="Y"
    fi
    

    Script now assumes it has enough information to proceed. Next code section in script is for downloading the 2 export files – the WXL and the TAR – from the provided URL. It is summarized because it is proprietary information that is subject to change, depending on the whims of WordPress.com. This what we mean, when we say a “HTML-scrape” of commands, to login into wordpress.com, and download. Below, you have provided the URL of your WordPress.com site, and your username.

    It will skip the next section, if you provided the name of the WXL and TAR files, and it previous found the files.

    # Getting exports remotely
    if [ "$IS_WXL_AND_TAR_EXISTS" != "Y" ]; then
      WP_USERNAME_FILE=$2  WordPress.com username is in 2nd argument
      WP_USERNAME=$(basename $WP_USERNAME_FILE)
      if [ "$WP_USERNAME_FILE" == "" ]; then  exit with error 1, if username is blank
        ... exit 1
      fi
      if [ ! -f "$WP_USERNAME_FILE" ]; then  exit with error 2, if there is no file with same name as username
        ... exit 2
      fi
      WP_PASSWORD=$(<$WP_USERNAME_FILE)  WordPress.com password, is in contents of file, with same name as username
    
      ...very long list of commands for HTML-scrape, removed for brevity...
    
    fi
    

    By now, it has finished downloading the TAR and WXL export files.

    OR you have already downloaded the TAR and WXL file manually, thru the administration tool that WordPress.com’s website provides you, and you have renamed them to have same name (except the extensions).

    The next commands in the script file, automates downloading Docker containers for WordPress software for Linux, and installs your downloaded content in the TAR and WXL file to them.

    #===========Below, is container start, and running import in container=============
    # Verifying files are valid
    echo "Examining export file $WXL_FILE"
    grep '[^<]' $WXL_FILE  wp-cli export creates a different export file, so it needs to be fixed
    if [ $? -eq 0 ]; then
      ...temp fix... deleted for brevity... better to use export from Web, not wp-cli
    fi
    
    # Prepaing wordpress config and containers
    ...deleted for brevity... surmising the most likely name that docker will assign the containers
    echo "Using $CONTAINER_PREFIX as container name"
    
    USED_LOCAL_PORTS=$(docker ps --format '{{.Ports}}' | grep -o  :[0-9]*-)  get list of ports on host, used by other docker containers
    NEW_PORT=8888    ports assigned to containers created by this script start at 8888
    echo $USED_LOCAL_PORTS | grep ":${NEW_PORT}-" &>/dev/null  does 8888 exist in used ports?
    while [ $? -eq 0 ];do  if previous command was NOT FOUND, then run below
      echo "$NEW_PORT : is unavailable on this host"
      NEW_PORT=$(( NEW_PORT + 1 ))
      echo $USED_LOCAL_PORTS | grep ":${NEW_PORT}-" &>/dev/null
    done  keep running previous commands, increasing port#, until a port is found not in the list
    ... deleted for brevity...
    
    grep prefix docker-compose.yaml
    ... deleted for brevity...backup original docker compose file, which is incomplete
    
    ... deleted for brevity...
    
    sed -i "s/prefix/$CONTAINER_PREFIX/g;s/HOST_PORT/$NEW_PORT/g" docker-compose.yaml  Complete docker-compose.yaml with new container name and host port# assignment
    
    
    echo "starting wordpress containers"  Next 3 lines, start WordPress containers
    docker pull wordpress:latest  Copy WordPress container from Docker
    docker pull mysql:latest  Copy MySQL container from Docker
    docker-compose up -d  Start the containers, indicated in docker-compose file, in background
    
    WORK=$(pwd)
    CONTAINER_NAME="$(basename $WORK)_${CONTAINER_PREFIX}php_1"  Surmising automatic name of Docker container
    ... deleted for brevity... verifying the surmised names, exist in started docker containers
    echo "Verified container names are: $CONTAINER_NAME $SQLCONTAINER_NAME"
    
    sleep 30  hope the containers finish start in 30 sec
    AGAIN="y"
    while [ "$AGAIN" == "y" ]; do
      ... deleted for brevity... verifying that wordpress container is responding to HTTP requests
    done
    
    grep "HTTP/1.1 302 Found" wordpress.html
    if [ $? -ne 0 ]; then  exit with code 2, if expected redirect CODE not returned by wordpress
        ...  exit 2
    fi
    grep "Location: http://localhost:$NEW_PORT/wp-admin/install.php" wordpress.html
    if [ $? -ne 0 ]; then exit with code 2, if expected redirect URL not returned by wordpress
        ... exit 2
    fi
    
    
    # configuring wordpress, and installing content
    # installing wp-cli
    Next 4 lines, download wp-cli to WordPress PHP container, and installs it
    docker exec $CONTAINER_NAME  curl https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar -o /tmp/wp-cli.phar
    docker exec $CONTAINER_NAME  php /tmp/wp-cli.phar --info
    docker exec $CONTAINER_NAME  chmod +x /tmp/wp-cli.phar
    docker exec $CONTAINER_NAME  mv /tmp/wp-cli.phar /usr/local/bin/wp
    
    # copying the data downloaded from live site, to container
    Next 2 lines, moves the 2 export files, into container's file system
    docker cp  $WXL_FILE   $CONTAINER_NAME:/tmp
    docker cp  $TAR_FILE   $CONTAINER_NAME:/tmp
    
    # replace PHP for wordpress
    # https://www.wpbeginner.com/beginners-guide/which-wordpress-files-should-you-backup-and-the-right-way-to-do-it/
    # wp-config.php
    # .htaccess
    # wp-content/*
    Next 6 lines, installs the media TAR file
    docker exec -w /var/www/html/wp-content/ $CONTAINER_NAME  tar xvf /tmp/$TAR_FILE
    docker exec -w /var/www/html/wp-content/ $CONTAINER_NAME  rm /tmp/$TAR_FILE
    docker exec -w /var/www/html/wp-content/ $CONTAINER_NAME  chown www-data upgrade
    docker exec -w /var/www/html/wp-content/ $CONTAINER_NAME  chgrp www-data upgrade
    docker exec -w /var/www/html/wp-content/ $CONTAINER_NAME  chown www-data [0-9][0-9][0-9][0-9]
    docker exec -w /var/www/html/wp-content/ $CONTAINER_NAME  chgrp www-data [0-9][0-9][0-9][0-9]
    
    # run import of export file
    LOCAL_WP_URL="$(hostname):$NEW_PORT"  URL as far as WordPress knows
    Line above is tricky, because the port number doesn't configure WordPress for Linux's in the container's TCP listening port at all.  The container always believes it is receiving port 80.  The docker-compose.yaml configuration, which was the 8888 and up change previously mentioned, reserves port number on the container host, for the host to listen to, and forward to the container as port 80.  WordPress in the container, the apache process that is listening, always believes it is listening to port 80.  The configuration above, is solely used for wordpress to generate full path URL's used in links and redirects. 
     And this value is used in the "wp core install" line below
    
    NEW_WP_ADMIN="admin"
    ...deleted for brevity... creating a new user and password named "admin" for WordPress for Linux
    Next line starts a new WordPress site, with the wp-cli tool
    You can do the same thing, thru the wordpress container site, which is up already
    docker exec -w /var/www/html/ $CONTAINER_NAME  wp core install --allow-root --url=$LOCAL_WP_URL --title=Test.$WP_URL  --admin_user=$NEW_WP_ADMIN --admin_password=$NEW_WP_PASSWORD --admin_email=$NEW_WP_ADMIN@localhost.localdomain
    
    Next line installs WXL importer
    docker exec -w /var/www/html/ $CONTAINER_NAME  wp plugin install wordpress-importer --activate --allow-root
    Next line imports the WXL file
    docker exec -w /var/www/html/ $CONTAINER_NAME  wp import /tmp/$WXL_FILE --authors=create --allow-root
    Next line removes the WXL file
    docker exec -w /var/www/html/ $CONTAINER_NAME  rm /tmp/$WXL_FILE
    Next line installs a common theme, to show that the site changes
    docker exec -w /var/www/html/ $CONTAINER_NAME   wp theme install twentysixteen --activate
    
    # Install googlemap embed shortcode from a local zip file
    docker cp  bob-shortcode-plugin.zip   $CONTAINER_NAME:/tmp/  Copies a PHP plugin, I wrote to restore some functionality I saw was missing in WordPress software, available in WordPress.com
    docker exec -w /var/www/html/ $CONTAINER_NAME  wp plugin install /tmp/bob-shortcode-plugin.zip --activate  Installs above PHP plugin
    
    # update the URL, to match docker-compose's port forwarding
    # This may have to be modified, depending if you do reverse proxy
    ...deleted for brevity... The script gets the username and password to MySQL from docker-compose.yaml.  Then modifies "update_url.sql".  You may need to run the script "update_url.sh", if you use a reverse proxy, in front of your container.  The SQL statement removes the port number from the WordPress URL configuration, that it appends to URL and redirects
    docker exec -i $SQLCONTAINER_NAME mysql -u $USR -p$PWD < update_url.sql
    
    # create container image
    ...deleted for brevity... Ignore the commands to upload the container with all the exports imported, as a image to AWS ECR repo.  This will be moved to different shell script
    
    echo done
    Next line shows the URL you should be able to connect to WordPress with
    echo "You can access your wordpress here: $LOCAL_WP_URL"
    Next line shows the admin user and the password to login with, to the new WordPress
    echo "please login to wordpress /wp-login.php with: $NEW_WP_ADMIN/$NEW_WP_PASSWORD"
    

    That completes the explanation of “containerize_wordpress_com.sh”

    ———————-

    Why is this a Fantastic Failure?

    This was supposed to be straightforward. It is not. WordPress.com made many customizations on their site, that doesn’t translate without work. It is a Fantastic Failure, b/c I think you would be interested in what is involved in migrating your content off WordPress.com, to your own servers. And it is almost a fantastic failure, b/c I’ve coded some workarounds.

    Do you need to know the WordPress version, of WordPress.com, to execute this script

    You shouldn’t need to know the wordpress, php and mysql versions to execute this script, as it assumes that the latest wordpress image has the right PHP installed, and works with the latest mysql image. And we are not, altering any of the default settings for a new installation in this script. But each version of wordpress is particular to which versions of PHP and mysql it wants to work with. So if you need to know for some reason (such as experimenting with one of the other options mentioned earlier), you may need to lookup versions for each software. This script also assumes that the export formats from WordPress.com, are agonistic to the latest versions of WordPress software on Linux.

    Why can’t I make exact copy of WordPress.com site?

    The software on WordPress.com has been heavily customized for their own company’s purposes. There are no defaults I am aware of, to replicate this easily on the Linux version of WordPress. It is a hunt and peck process of finding what functionality is different, and searching for replacement.

    The export/import process supported by WordPress.com (and the Linux version of WordPress) is limited in what it transfers, to mostly tags, categories, posts, menu items, and to different level of support-your media files. This process however, is supported by most versions of WordPress on Linux. Which means you can upgrade, to future WordPress functionality.

    This is what is meant by the 3rd option.

    I’ve seen total copies of WordPress from one computer to another?

    I suspect you saw a complete copy of the WordPress directory, and a complete database dump of the mysql database. Though it is possible that this works without verifying the php, and mysql platforms on the destination host, the sure way to make it work, is to make sure that the PHP and mysql version on the destination, matches the original source WordPress. This means no upgrades supported. But if all you wanted was automated exact copy, this is it. This is the 2nd option mentioned earlier.

    How do I find the right docker images, if you need a different version of WordPress and MySql, than the latest versions

    WordPress version:

    cat wp-include/version.php

    PHP version:

    php -v

    mysql version:

    show variables like ‘%version%’;

    See link for compatible versions:

    WordPress Compatibility

    Need to find right docker container for WordPress. Find closest match to WordPress and Php. if you can’t find exact match, find the closest php version. Copy the pull command. The versions of WordPress Docker images are below:
    https://hub.docker.com/_/wordpress/tags
    Find the tag of number that best matches the WordPress version you want, that matches the PHP version you need. You can ignore fpm (as this is a feature I don’t understand), and you can ignore the web server that the PHP platform is being managed under.

    The versions of WordPress MySQL images are below:
    https://hub.docker.com/_/mysql/tags
    Find the tag of number that best matches a compatible MySQL, to the above WordPress image you select. You can ignore the operating systems the image is supposed to emulate.

    The images can be then replaced in the docker-compose.yaml file, and run

    docker-compose up

    to bring up this environment.

    Why is plugin added? Why can’t I find it with WordPress. And who wrote it?

    I wrote it. It isn’t registered by WordPress, so you can’t find it. It doesn’t do anything evil. You can see what is in the code, in the wp-content/plugins/bob-shortcode-plugin. I have very little experience with PHP. I just wrote it, to replace functionality missing that I saw, when I migrated my site to a local copy. The googlemaps] shortcode isn’t in WordPress by default. The code seemed easy, so I wrote my own plugin for it. The gallery defaulted to thumbnail in Linux’s image gallery, and it didn’t seem that difficult to override it, to use medium images. imageblocks format the same, in both WordPress.com and Linux WordPress. But you can click on images in WordPress.com’s images, to get enlargement. I added my own code, to do it, is a slightly different way. the gallery] short code in wordpress.com, formats and justifies the images in a mosiac pattern by default. I applied this pattern to both gallery] images and imageblock images.

    Why does your script copy cookies?

    This is how most HTTPS based login processes work. You are given a unique code, after logging in. This code is stored in a cookie. It is retransmitted back to server, with every request, to uniquely identify you. The cookie, is also known as a session. The session is protected from hijacking, by transmission within a HTTPS encrypted data stream. But the browser decrypts it. The script copies it. Then re-sends it, to get the exports, with your authentication details.

    Will this work for copying WordPress on Linux to another WordPress on Linux?

    Not without modification. WordPress.com’s export is customized for itself. I actually have a script to export WordPress on Linux, to WordPress on Linux, but I didn’t make it available b/c I wrote it for my own site. And there are details in there, I need to clean out. And I’m too lazy to do so.

    Why does it keep saying “database connection cannot be established” for more than 5min

    This means the information between the 2 sections in the docker-compose don’t match. The script is supposed to make them matching, but if somehow you have a problem with this, this is the most likely culprits
    – The database hostname in PHP container, doesn’t match the network alias in the MYSQL container section
    – The database name PHP container, doesn’t match the MySQL initial database creation parameters (usually in MYSQL container section, when new)
    – The database username in PHP container, doesn’t match the MySQL initial database creation parameters (usually in MYSQL container section, when new)
    – The database password in PHP container, doesn’t match the MySQL initial database creation parameters (usually in MYSQL container section, when new)
    – Worst case, something really weird happened, and the two containers are in 2 different networks and can’t resolve each other’s hostname OR can’t route to each other. Execute a shell into php container:

    docker exec -it (php container name) bash
    

    Then run “curl -v http://(mysql alias)” in the container. It won’t connect, b/c curl tries on port 80, but this diagnostic step should rule out problem Docker’s DNS configuration for MySQL, by noticing that the hostname is resolved to IP4 in output. If DNS resolution works, then try “curl -v http://(mysql alias):3306”, to see if you get TCP/IP connection, but bad response. You only have “curl -v” in the container filesystem to try to diagnose the problem.

    Why do I need to know about ports for Docker? And the new URL for WordPress

    “…During the WordPress installation process WordPress captures the hostname and port used to access the newly installed CMS. This information is stored in the backend MySQL database, and is used to force redirect requests to the correct hostname and port…”

    https://www.serverlab.ca/tutorials/linux/web-servers-linux/how-to-change-port-80-to-8080-for-wordpress/

    What does this mean? What your browser sends, looks like below:

    bob:~/containerize_wordpress_com$ curl -v http://localhost:8889
    * processing: http://localhost:8889
    *   Trying [::1]:8889...
    * Connected to localhost (::1) port 8889
    > GET / HTTP/1.1
    > Host: localhost:8889
    > User-Agent: curl/8.2.1
    > Accept: */*
    > 
    

    What it gets back, looks like

    < HTTP/1.1 301 Moved Permanently
    < Date: Fri, 05 Jul 2024 19:24:33 GMT
    < Server: Apache/2.4.59 (Debian)
    < X-Powered-By: PHP/8.2.20
    < X-Redirect-By: WordPress
    < Location: http://localhost/
    < Content-Length: 0
    < Content-Type: text/html; charset=UTF-8
    < 
    * Connection #0 to host localhost left intact
    

    Above is a request to localhost:8889, when the port in request, doesn't match wordpress site url config. Below is what happens, when the WordPress site ip address, matches request's ip address, but not the port. It will redirect to the wordpress config.

    C:\Users\Bob\Documents>curl -v http://192.168.137.141:8889/ | more
    * Connected to 192.168.137.141 (192.168.137.141) port 8889
    > GET / HTTP/1.1
    > Host: 192.168.137.141:8889
    > User-Agent: curl/8.4.0
    > Accept: */*
    >
    
    < HTTP/1.1 301 Moved Permanently
    < Date: Sun, 07 Jul 2024 21:15:54 GMT
    < Server: Apache/2.4.59 (Debian)
    < X-Powered-By: PHP/8.2.20
    < X-Redirect-By: WordPress
    < Location: http://192.168.137.141/
    < Content-Length: 0
    < Content-Type: text/html; charset=UTF-8
    <
      0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
    * Connection #0 to host 192.168.137.141 left intact
    

    And finally, below is a demonstration that WordPress seems lax and processes the request, when the wordpress site configuration is localhost, but WordPress port matches the host header port.

    C:\Users\Bob\Documents>curl -v http://192.168.137.141:8889/ | more
    Connected to 192.168.137.141 (192.168.137.141) port 8889
    > GET / HTTP/1.1
    > Host: 192.168.137.141:8889
    > User-Agent: curl/8.4.0
    > Accept: */*
    >
    

    A "200 OK" response code, means no redirect. And it is sending back content.

    < HTTP/1.1 200 OK
    < Date: Sun, 07 Jul 2024 21:20:45 GMT
    < Server: Apache/2.4.59 (Debian)
    < X-Powered-By: PHP/8.2.20
    < Link: ; rel="https://api.w.org/"
    < Vary: Accept-Encoding
    < Transfer-Encoding: chunked
    < Content-Type: text/html; charset=UTF-8
    <
    { [2639 bytes data]
    
    ...
    
    ...
    

    Notice above request is putting IP address into Host header. I confirmed the WordPress database says for it's home URL is http://localhost:8889. The ports match, but the DNS name does not. So your site config has to have to port match the docker config which has to match the browser url, or reverse proxy needs to send data to the docker port forward and rewrite browser requests to what the wordpress site config expects.

    If the "Host" HTTP Header in the request that WordPress processes, doesn't match it's own information, it sends back to visit the correct URL.

    In your containerized solution you now manage yourself, you have to manage ports yourself. B/c of the feature mention above, wordpress software will keep trying to forward to what it thinks is it's URL, if it received a request asking for a different URL. My script will default the registered URL+port you indicate to the script, to match the port forwarding to docker. This is going to be a little confusing, if you ever have to change it.

    TLDR: The port on container host, has to match the wordpress port configuration (scenario 1 and 2 results in incorrect redirect). And the DNS for the container, doesn't have to match the wordpress configuration, if your wordpress configuration url is to localhost (so it seems in the 3rd scenario). BUT it does use the site URL in page links, so those will all be broken, if the configuration doesn't match.

    So the only foolproof way of handling this, the browser request has same ip address and port, as the wordpress site url config, and the docker port forward listens on that port, then it works well.

    How to check:
    1.get the values from Mysql:

     
    docker exec -it mysql -u [wordpress username in docker-compose.yaml] -p[wordpress password in docker-compose.yaml] [mysql container name]
    

    Execute these statements

    SELECT option_value FROM wp_options WHERE option_name='siteurl’;
    

    looks like ’http://[DNS]:[port]’

    SELECT option_value FROM wp_options WHERE option_name='home’;
    

    looks like ’http://[DNS]:[port]’

    Find the port forwarding in docker

    docker ps | grep [wordpress php container name]
    

    It is going to be -p[container host's port]:80
    [container host's port] must == [port]
    or WordPress will forward it to http://[DNS]:[port]
    and when you enter the address in the

    2. Execute (windows)

    ipconfig

    or (linux)

    ipconfig

    on the machine hosting the container. Look for IPv4 address. or even IPv6. This is [container host actual IP address]

    Execute

    nslookup [DNS]

    on the machine you will use a web browser on.
    This is the [locally DNS registered IP address] of your container host
    [container host actual IP address] must == [locally DNS registered IP address] or it wont work

    Even a hosts file, spoofing the DNS name, should work.

    But this is something you have to manage yourself about your wordpress container, and your workstation that you use to browse to it

    Details:
    Your browser doesn't know better and directs the HTTP request to the DNS address. However, HTTP header host is taken "cut and pasted" from the browser's address field, as almost all browsers do.
    1. If you use IP address in broser instead, it will forward. bc "HOST:" http header doesnt match wordpress's site url config.
    2. even though the wordpress PHP container is configured to use port 80, and [port] is container host's port, you need to use the [container host's port] in the browser b/c it is included in the HTTP header "HOST:". And this header, doesn't translate into what port the TCP connection OS object in the container (representing to container what a TCP connection is to it). And it is supposed to match the TCP connection port from the browser, to the container host. But obviously, this can be altered with a spoofed DNS entry.

    Ref: https://www.serverlab.ca/tutorials/linux/web-servers-linux/how-to-change-port-80-to-8080-for-wordpress/

    Better to have a little technical knowledge how how port forwarding works, and how HTTP requests are sent.

    ps. You can bypass wordpress's URL check, with a code change. It is a hack really. But I think it always works, and ignores the Host header, bc it always lies to wordpress what the wordpress's configured URL is, is always what is sent.

    link to the swarm article to see code hack

    ps2. I assume they put this URL check in, for a reason. I would not recommend pushing this hack to a production server. A production server, should have a registered DNS and static IP address. You should not be messing around w changing configurations to support browser clients constantly.

    Pop from SortedStack A, push to SortedStack C
    Pop from SortedStack A, push to SortedStack B
    Pop from SortedStack C, push to SortedStack B
    Pop from SortedStack A, push to SortedStack C
    Pop from SortedStack B, push to SortedStack A
    Pop from SortedStack B, push to SortedStack C
    Pop from SortedStack A, push to SortedStack C
    If you didnt recognize that as the Tower of Hanoi, then maybe you need to get out and get some fresh air.
    --Some frustrated dude

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    Copyright © 2025 TictAwf.com — Velux WordPress theme by GoDaddy