Migrating WordPress from Pagely

Pagely is an expensive and robust solution for WordPress hosting. With the right caching setup wordpress can be performant, so let’s slap it in a docker container behind nginx.

To get off of Pagely, the most critical thing you’ll need to do with your exported backups is to make sure to either remove or rename or remove the mu-plugins folder.

  1. Rename or delete mu-plugins/ from the folder export.
  2. Import the database and wp-content directories.

What’s easier than physically moving your wp-content directory is using the Updraft Plus plugin to create a backup of your wordpress install.

Redirect Hell

Setting the siteurl and home settings in the database shoots me into redirect hell.

 

Setting as localhost instead of localhost/blog yields a somewhat more functional site, but all the links are broken and nothing tends to work. I must need PHP 5. (This was definitely not the solution)

So it all works after disbabling the pagely plugins but this reverse proxying to a docker container from a subfolder thing, wordpress really doesn’t appear to like it very much. Everything worked for a second but now it doesnt again, just stuck in a 301 redirect loop to itself. The wp-admin functions fine as long as you remember to add the trailing slash on the URL.

Endless redirect loops later, we’re still stuck in a redirect loop.

Hopefully you won’t need to spend that much time dickerin with it.

wp-config.php

define('FORCE_SSL_ADMIN', true);

define('WP_HOME', 'http://example.com/newblog/');
define('WP_SITEURL', 'http://example/newblog/');

$_SERVER['REQUEST_URI'] = '/newblog' . $_SERVER['REQUEST_URI'];

This $_SERVER['REQUEST_URI'] line was the most helpful fix I came across. I had previously been using $_SERVER['REQUEST_URI'] = str_replace("/wp-admin/", "/blog/wp-admin/", $_SERVER['REQUEST_URI']); as recommended by several resources in place for the wp-admin but rewriting the whole URI with $_SERVER['REQUEST_URI'] = '/newblog' . $_SERVER['REQUEST_URI']; stopped redirect hell.

/etc/nginx/sites-enabled/default

We’ll add a section for nginx to proxy to the wordpress container.

    location /newblog/ {
        access_log off;
        auth_basic off;

        rewrite /newblog/wp-admin$ $scheme://$host$uri/ permanent; # This line redirects /newblog/wp-admin to /newblog/wp-admin/ which is nice to have. 

        proxy_set_header  Host               $host;
        proxy_set_header  X-Real-IP          $remote_addr;
        proxy_set_header  X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header  X-Forwarded-Proto  $http_x_forwarded_proto;

        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_read_timeout    90;
        proxy_connect_timeout 90;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Proxy "";

        proxy_redirect    off;
        proxy_pass        http://wordpress/;
    }

.htaccess

The .htaccess file that wordpress creates will attempt to make the RewriteBase and RewriteRule include the newblog/ part of the URL, which we don’t want, and will cause a redirect loop.

# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

The deploy

So it all works after destroying and rebuilding containers. What are the steps to do it live?

  1. ✅ Install Updraft Plus and create a backup, stuff it in dropbox.
  2. ✅ Deploy the containers, on the /newblog/ URL.
  3. ✅ Run our install script via wp_cli:
#!/bin/bash

docker-compose run wp_cli core install --url='http://example.com/newblog/' --title=temp --admin_user=temp [email protected] --admin_password="password"
docker-compose run wp_cli plugin install updraftplus --activate
  1. ✅ Connect dropbox in the updraft plus plugin. Click rescan remote storage, select the backup to install, and restore that backup.
  2. ✅ Reset the siteurl and home options in the wp_options table.
mysql -uroot -psecret -h 0.0.0.0 wp_database -e 'update wp_options set option_value = "http://example.com/newblog" where option_name = "siteurl" or option_name = "home"'
  1. 💣 Make sure it all works!
  2. ✅ Remove the old nginx redirect for the /blog url and replace it with the /newblog directive. Update the wp-config.php and the database to remove the references to /newblog.
  3. ✅ Shut down pagely. Keep your money.

HTTPS Support.

We didn’t test SSL support locally before deployment, and it’s easy to bang your head against the wall chasing down a fix for a problem that’s the result of something else.

Turns out that Jeff’s Application Load Balancers handle SSL termination and thus pass http_x_forwarded_proto. We set that right in the nginx config and suddenly there is no more redirect hell, and everything’s running on https.

The line in the nginx config proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; must use x_forwarded_proto instead of $scheme since we’re behind an ALB on AWS. This is only needed if you’re using nginx behind an application load balancer on aws, otherwise using $scheme should allegedly work.


Resources

github ↗ a5hleyrich/wordpress-nginx
docs.j7k6.org ↗ Basically looks to be exactly what we are looking for, but not quite.
stackoverflow ↗ nginx subpath to redirect to wordpress docker container

serverfault ↗ hosting a wordpress blog using nginx as a sub directory
stackoverflow ↗ wordpress nginx proxy and subdirectory wp login php redirects to domain

stackexchange ↗ wordpress wp admin https redirect loop

stackexchange ↗ https leads to sorry you are not allowed to access this page
stackexchange ↗ setting server https on prevents access to wp-admin

codex.wordpress.org ↗ administration over ssl

serverfault ↗ x forward proto custom header

Generating ERD for Django Applications

Generating an ERD (Entity Relationship Diagram) can be helpful to understand what your database looks like, and is also really easy to generate if you’re running a Python/Django Application.

Step 1: Install django-extensions and graphviz

 pip install django-extensions && pip install graphviz

Step 2: Add django_extensions to settings.py

INSTALLED_APPS = [
    ...
    'django_extensions',
    ...
]

Step 3: Create the .dot output and convert to .png

Run manage.py graph_models from the environment you may normally use:

python manage.py graph_models -a > output.dot

From your mac, change the format to png using graphviz

brew install graphviz
dot -Tpng output.dot -o output.png

Note You can also output to pdf by changing the type:

dot -Tpdf output.dot -o output.pdf

References
Django Extensions graph_models docs
Django Extensions Commands Unavailable?
Opening .dot files on mac