How to use UpdraftPlus when The Bad Thing™ happens

I am in the process of handing over a site to someone who’s not used WordPress before and doesn’t necessarily know where what lives and how. I thought it would be a good idea for me to document how to use the free UpdraftPlus plugin.

I use the commercial version of this plugin because it is fire-and-forget for my multisite installation. But if you are running a standalone installation of WordPress then the free version is a good suitable option. Continue reading “How to use UpdraftPlus when The Bad Thing™ happens”

Did I mention I like WP-CLI?

I’ve written praise for wp-cli before but it’s a toy that will never get old for me.

I was working on this problem for a friend and I needed to create a test multisite installation. I have a domain I can use aside from my main one so I setup another nginx virtual host, setup the DNS entries and used Let’s Encrypt to obtain legitimate X.509 certificates.

For creating the DB and WordPress config I used CLI commands.

$ mysql -u root -p

create database leeloodallas;
grant all privileges on leeloodallas.* to 
"brucewillis"@"loc1alhost" identified by "5oM3U36ul$tringH3re";
flush privileges;

$ wp core download

$ wp core config --dbname=leeloodallas \
--dbuser=brucewillis \
--dbpass=5oM3U36ul$tringH3re \
--extra-php <<PHP
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

$ wp core install --admin_user=yourlogin \
--admin_password=Y3a2n0tHaP3n1ng \ \ \
--title="Leeloo Dallas Multisite"

$ wp core multisite-convert --subdomains

Yes, all the passwords and IDs are changed.

When I get into deep water (and I did) I just rm * -rf in the virtual host’s directory and in mysql drop database leeloodallas; and do it all over again.

The only thing different from other times is the wp core multisite-convert --subdomains command. I already have cookie cutter nginx configs and DNS is fire and forget. Once I had the vhost setup the Let’s Encrypt commands (also scriptable) was trivial.

WP-CLI is cool and scripting this is such a time saver.

2FA should be built into WordPress core

Does email work with your WordPress installation? When someone leaves a comment on your blog or your WordPress installation automatically updates to a minor version number such as 4.4 to 4.4.1 do you get that email?

You did get those emails? Great! Now go, install and activate the Two Factor Authentication plugin maintained by George Stephanis. I’ll wait.

Now that you have done that, on the top right corner of your dashbaord is a “Howdy, User” link. Click that and select Edit My Profile. Scroll down on your profile page and enable the first two options. That’s “Email” and “Time Based One-Time Password (Google Authenticator)”.


I made the Google Authenticator my primary means of logging in. I keep the app on my password protected iPhone, it’s a one-time password (OTP) generator and it doesn’t need access to Google to work. It’s time based after all.

What is two factor authentication (2FA)?

2FA is a means to increase the confidence when you log in that you are in fact who you say you are.

When you log into WordPress, you use an ID and password. The security is in the password and should be along the lines of “gHJjgbtjXa9FLyGkhaHR0o” which I got courtesy of my 1Password app. That password is one factor of authentication. Your password is something that you know.

The second factor is what you have in your possession. In my case it’s my Google Authenticator app on my iPhone.

When I log into my WordPress site I am prompted for my username and password. Once that is successful I am then asked for my authentication code.


Which I get from my app. If that does not work then I click on the backup method and soon get a code via email. I enter that code and I am in, which is why I asked if mail works at the beginning of this post.

Mail needs to work. So does good time keeping.

My multisite installation is on a VPS and I run NTP. I have to because on a VPS the time will drift (on anything really) and if my server’s time is far enough out of sync then my OTP will not work. Or my phone could be dead but I still can access my email.

By configuring the email as a fallback I have another way to get into my installation. That email code is good till it’s used or is replaced and can get you out of a bind.

2FA needs to be built into core

Having 2FA in WordPress as a built-in option moves the security bar farther.  It increases the security posture for users and if it is an option, if it’s easy to setup then it will be adopted by users.

Yes, it will take some education for people to use it properly but that is not insurmountable.

In the past, users would install WordPress and forget to maintain them. The other day I came across a 3.5.2 installation. That was released in July 2013. In Internet years that’s ancient and there are several known exploits out there. The 3.5.x code isn’t maintained.

As of version 3.7 minor release updates are turned on automatically by default. If you installed 3.7 and did not do anything else then as of today you are or will be running 3.7.12 shortly. Major version upgrades are not automatic so 3.7.x will not update to 3.8 or even to the current 4.4.1. The major versions need to be updated by the user initiating that upgrade, although some forward thinking hosts will do it for you anyway.

Automatic updates are a result of the developers wanting the environment to become more secure. Unpatched WordPress installations were the cause of compromised sites that sent spam, spread spammy links and made the Internet neighborhood a worse place to be.

It also gave WordPress an unjustifiable reputation for being insecure because users did not maintain their code.

Having 2FA is similar to enabling TLS on your WordPress installation. If your server supports HTTPS just update your Site URL and WordPress Address, perform a little search and replace for the old http:// references to their TLS versions and you are done. More and more sites are defaulting to https because it’s easy.

2FA is like that, it’s a step in the direction of users taking their security into their own hands. It’s educational too, meaning that once it’s setup and working you’ve learned something new.

What about the Support Team’s concerns?

Mika Epstein, myself and others expressed reservations not about having 2FA built into WordPress. We like this idea. Our concerns were along the lines of “How can we walk the user through disabling 2FA if they bork it badly?”

The idea we expressed was that this should be enabled by editing the wp-config.php file by hand, just as you have to do when you enable multisite. If you can do that successfully then you are technical enough for 2FA. The words I used were “you need to be this tall to enable this feature”.

I don’t think that anymore. If someone’s email is working then they can get back into their installation with the emailed access code.

What I’d like to avoid is the situation that exists with password resets. If you look at the WordPress Codex article about resetting your password then you may understand.

For manual password resets I encourage users to add a line to their theme’s functions.php file but that can be dicey. If they typo that file they can break their whole site. That’s still more appealing for me than trying to walk a user through using phpMyAdmin.

Manual password resets is difficult for regular users. If they can enable 2FA and have a not too difficult way to disable it then any reservations I’ve had are gone. I know this is being worked on and I would really like to see this properly put into WordPress 4.5.

It’s something that can make the Internet neighborhood a more secure place to be.

Let’s Encrypt is all kinds of awesome

I had some time and did a git pull on the Let’s Encrypt github page. This is a project that makes it easy to install and maintain free X.509 certificates for web servers. The certificates are in PEM format and can be easily used for any server app but usually it’s just for HTTPS on web servers.

Requesting your own certs

The first time I ran the ./letsencrypt-auto command it used apt-get to download its dependencies. The integration with Ubuntu is nice and works well. A few minutes later of some prodding and poking, meaning I read the Let’s Encrypt User Guide, I gave it a shot.

On my VPS I selected and ran the following command as root.

./letsencrypt-auto certonly --webroot -w /var/www/vhosts/ -m not@my-email.btw -d

The site is on my WordPress network so the directory is the same. The end result of that was to politely create and place these symlinked files.


A quick update to my nginx config for

ssl_certificate /etc/letsencrypt/live/;
ssl_certificate_key /etc/letsencrypt/live/;

I checked with “nginx -t” and “service nginx restart” and that was it.

Encryption has never been this easy

The certificate is valid for 90 days and is recognized by all browsers.

To renew it I’ve created a cron job for the first of every month to run this command.

./letsencrypt-auto certonly --webroot -w /var/www/vhosts/ -m not@my-email.btw -d -d --renew

Which is the same command with just --renew added to it. Easy. If you don’t renew the CA will send you a reminder at the email you specified via the “-m not@my-email.btw” command line argument.

I’m not directing the output to /dev/null because if that cronjob works or not I want to see that output. If the cronjob fails then I can always run the command by hand.

Will I switch all my domains to Let’s Encrypt?

Why not? The project is currently in a public beta and the Let’s Encrypt tools will change and continue to be developed. But for the next 90 days the certificate I obtained will work fine. Even better if they automatically renew.

What I am looking for is a reasonable expectation of privacy between my web server and my visitors. I do not use TLS for authentication and the Let’s Encrypt certificates work fine.

If I had an online store then I might consider getting an Extended Validation Certificate but that would be only to reassure visitors when they are making a purchase. EV certs are not cheap. Let’s Encrypt is free so it’s not a hard decision for me to make.

This helps protect the traffic from casual snoopers between my server and your browser. It’s not a magic bullet for security but the wide spread adoption of encryption will help promote privacy.

My oEmbed discovery links work (It was me)

I thought I broke my oEmbed discovery links but I had a more fundamental problem. I had broken fancy permalinks on my nginx configuration for a while and didn’t realize it.

I revisited the Nginx Codex page and did a stare and compare of my configuration and the examples there. I am sure I read that page in the past and my mistake was the “try_files” line.

Here’s what I had for try_files.

location / {
	try_files $uri $uri/ /index.php;

Here’s what that line should have read.

location / {
	try_files $uri $uri/ /index.php?$args;

See the “?$args” part? With that in place the non-post URLs work. The permalinks worked fine but things that were not to a post or page didn’t. Due to my fancy permalink settings my oEmbed discovery links had this format. and that wasn’t being handled by my nginx configuration.

My plugin worked because I was replacing the fancy URLs with the regular non-fancy “?rest_route” version which nginx passed along to my WordPress installation just fine.

This may have also broken other features as well. I wonder what else I’m missing? I should check all the things. 😉

oEmbed not working (I’m convinced it’s me)

One of the new WordPress 4.4 features is the ability for your installation to become an oEmbed provider. In plain English you can paste your post URL and get a result as if you were embedding a YouTube URL.

I could not get it to work for me. No way, no how. The json and XML discovery links were there in the post HTML but those links came back with “What? What? No. Go away, you’re bothering kid.”

It should have come back with a valid output and it did. It was a result, just not a functioning one.

For example, this post (which I’m not embedding) should provide via this link usable information. It doesn’t. I get this.

<link rel="alternate" type="application/json+oembed" href="" />

That link results in this.

{"code":"rest_missing_callback_param","message":"Missing parameter(s): url","data":{"status":400,"params":["url"]}}

It doesn’t contain any useful data except to reply with “What? What? What?”

It should output this.

{"version":"1.0","provider_name":"Mostly Harmless","provider_url":"https:\/\/","author_name":"Jan Dembowski","author_url":"https:\/\/\/author\/jan\/","title":"Server admins love WP-CLI","type":"rich","width":600,"height":338,"html":"</pre>
<blockquote class="\&quot;wp-embedded-content\&quot;">
<a href="\&quot;https:\/\/\/2015\/server-admins-love-wp-cli\/\&quot;">Server admins love WP-CLI<\/a><\/blockquote>\n<script type="text\/javascript">// <![CDATA[
\n<!--\/\/--><![CDATA[\/\/><!--\n\t\t!function(a,b){\"use strict\";function c(){if(!e){e=!0;var a,c,d,f,g=-1!==navigator.appVersion.indexOf(\"MSIE 10\"),h=!!navigator.userAgent.match(\/Trident.*rv:11\\.\/),i=b.querySelectorAll(\"iframe.wp-embedded-content\"),j=b.querySelectorAll(\"blockquote.wp-embedded-content\");for(c=0;c<j.length;c++)\"none\";for(c=0;c<i.length;c++)if(d=i,\"\",!d.getAttribute(\"data-secret\")){if(f=Math.random().toString(36).substr(2,10),d.src+=\"#?secret=\"+f,d.setAttribute(\"data-secret\",f),g||h)a=d.cloneNode(!0),a.removeAttribute(\"security\"),d.parentNode.replaceChild(a,d)}else;}}var d=!1,e=!1;if(b.querySelector)if(a.addEventListener)d=!0;if(a.wp=a.wp||{},!a.wp.receiveEmbedMessage)if(a.wp.receiveEmbedMessage=function(c){var;if(d.secret||d.message||d.value)if(!\/[^a-zA-Z0-9]\/.test(d.secret)){var e,f,g,h,i,j=b.querySelectorAll('iframe[data-secret=\"'+d.secret+'\"]'),k=b.querySelectorAll('blockquote[data-secret=\"'+d.secret+'\"]');for(e=0;e<k.length;e++)k[e].style.display=\"none\";for(e=0;e<j.length;e++)if(f=j[e],c.source===f.contentWindow){if(\"\",\"height\"===d.message){if(g=parseInt(d.value,10),g>1e3)g=1e3;else if(200>~~g)g=200;f.height=g}if(\"link\"===d.message)if(h=b.createElement(\"a\"),i=b.createElement(\"a\"),h.href=f.getAttribute(\"src\"),i.href=d.value,}else;}},d)a.addEventListener(\"message\",a.wp.receiveEmbedMessage,!1),b.addEventListener(\"DOMContentLoaded\",c,!1),a.addEventListener(\"load\",c,!1)}(window,document);\n\/\/--><!]]>\n<\/script><iframe sandbox=\"allow-scripts\" security=\"restricted\" src=\"https:\/\/\/2015\/server-admins-love-wp-cli\/embed\/\" width=\"600\" height=\"338\" title=\"Embedded WordPress Post\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\" class=\"wp-embedded-content\"><\/iframe>","thumbnail_url":"https:\/\/\/wp-content\/uploads\/sites\/2\/2015\/12\/wp-cli-rocks.png","thumbnail_width":600,"thumbnail_height":135}

Which is unreadable to you and I but to something looking to oEmbed your post it will look like this.

Server admins love WP-CLI

Nice huh? All neat in an iframe and easily embeddable. The output is customizable too and I plan to do that on my photo blog.

The oEmbed discovery links should just work but on my installations it doesn’t. I tried Apache2, nginx, clean installation with zero plugins and the Twenty Fifteen theme. Different servers too. I always got the wrong output and could not get oEmbed working.

During my troubleshooting I found a different URL that worked consistently for me. It’s the same information but with a filter I replaced the default output with one that worked for me.

Here’s the plugin code I used. The oembed_discovery_links is filterable (filters are cool) and I toss out the old links and replace them with my own.

This works for me but I do not like this solution.

The problem I have is that the normal links are not being replied to correctly via my WordPress installation. I don’t know why the default discovery links are not working. It bothers me, it really does. 😉

I’m convinced that there is something I’m doing wrong in my setup. Once I figure it out I’ll I can remove this plugin and I’ll post what I was missing.