Category Archive: Coding

Dev with Docker

I’ve been using Docker to run my local development environments for nearly two years now. In that time, it has gone from experimental and arcane, to almost stable and user-friendly.

Docker logoI work on a MacBook Pro, in OS X. After a brief dive into the details of what Docker is and how it works, you learn that you can’t run the Docker engine in OS X. Containers require process isolation and resource management features of the Linux kernel, so you can only run the Docker engine in Linux.

There are a number of workarounds for this, all of which involve using a virtual machine. Initially, I used boot2docker, which loaded a small VM using VirtualBox. Eventually, this was subsumed into Docker Machine and the Docker Toolbox, which used the same VM in VirtualBox but will slightly improved tools. Now I’m using Docker for Mac, which still uses a boot2docker-based virtual machine, but it runs on the hypervisor framework built into OS X, obviating the requirement for a separate hypervisor like VirtualBox.

With the notable exception of filesystem read performance, Docker for Mac has removed many of the more tedious aspects of running a local Docker environment, and had made development much easier.

This is the first in an anticipated series of posts documenting how I have my local development environment configured, focusing on using Docker for Mac for WordPress development.

Remove DEFINER clauses from MySQL dumps

If you have triggers or views in a MySQL database, a dump of that database will have clauses like:

/*!50017 DEFINER=`root`@`localhost` */

To import this dump into a new MySQL server (e.g., going from a production environment to local development), you’ll run into problems if you don’t have the same users defined on both systems.

As far as I can tell, there’s not an easy way to exclude these clauses from the dump, but with just a bit of post-processing, your SQL file can become portable. You can replace the user in the DEFINER clause with CURRENT_USER and it will use the current user when you import the SQL.

$ mysqldump > non_portable_dump.sql
$ sed -E 's/DEFINER=`[^`]+`@`[^`]+`/DEFINER=CURRENT_USER/g' non_portable_dump.sql > portable_dump.sql

Note: Depending on your version of sed, you might need to use the flag -r (for GNU sed) instead of -E (for BSD sed).

Add File Name to WordPress Media Browser

If you have a lot of images in your WordPress media library, especially if those images are visually similar, it can be somewhat awkward finding the correct file using the new media UI. You just have images, with no text to help identify them without clicking on each one.

media-browser

I wanted to add an overlay to each image so that I could see the filename, allowing easier skimming of the media library. The template for the HTML here comes from the function wp_print_media_templates(). It doesn’t really have any hooks for filtering the HTML, but we can wrap it in an output buffer and tweak it before rendering the template.

// hook in at the beginning of the footer to see if we need to add our wrapper
add_action( 'in_admin_footer', 'my_wrap_media_template_callback', 10, 0 );
 
// if the media templates are going to be rendered on this page, remove
// the default hook and put our wrapper in its place
function my_wrap_media_template_callback()  {
	if ( has_action( 'admin_footer', 'wp_print_media_templates' ) ) {
		remove_action( 'admin_footer', 'wp_print_media_templates' );
		add_action( 'admin_footer', 'my_wp_print_media_templates_wrapper' );
	}
}
 
// get the default templates, but add our HTML in the correct location
function wp_print_media_templates_wrapper() {
	ob_start();
	wp_print_media_templates();
	$output = ob_get_clean();
 
	// make sure to keep all of the whitespace here
	$to_find = '<div class="thumbnail">
					<div class="centered">
						<img src="{{ data.size.url }}" draggable="false" />
					</div>
				</div>';
	// this is the HTML that will render our filename
	$to_add = '
				<div class="filename">
					<div>{{ data.filename }}</div>
				</div>';
	$output = str_replace( $to_find, $to_find.$to_add, $output );
	echo $output;
}

A fairly simple wrapper. We’re just adding a <div> in the right spot, and WordPress handles the work of formatting it and populating the correct values.

media-browser-labeled

Integrate fail2ban with CloudFlare

Following my previous post about using fail2ban to stop malicious requests to xmlrpc.php, I set up a CloudFlare account. In doing so, I ran into two issues:

First, my access logs were only showing CloudFlare’s IP address, not those of the users making the requests. That’s due to how CloudFlare proxies every request. Fortunately, CloudFlare provides an Apache module to translate the IP addresses for your logs.

Second, even with the correct IP address in the logs, fail2ban was no longer effective in stopping requests (since it handled the requests before the Apache module translated the IP addresses). I needed to stop the requests at CloudFlare, before they ever made it to my server. Fortunately, it’s simple to set up a fail2ban action that utilizes the CloudFlare API to block those requests. Create an action including:

actionban = curl -s "https://www.cloudflare.com/api.html?a=ban&key=<ip>&u=<account>&tkn=<token>"
actionunban = curl -s "https://www.cloudflare.com/api.html?a=nul&key=<ip>&u=<account>&tkn=<token>"

And set your filter(s) to use that action.

Stop Hack Attempts on WordPress xmlrpc.php

I recently noticed a lot of requests to this and other WordPress sites’ xmlrpc.php file. By “a lot”, I mean about 10-20 every second. It wasn’t particularly breaking anything (there aren’t any currently vulnerabilities there that I’m aware of), but it was increasing the load on my server.

My first step was to set an .htaccess rule to give a 403 response. That at least avoided hitting PHP with all those requests. But Apache still had to process them, so I wanted to take it a step further. I’m already using fail2ban, so I wanted to figure out how to stop these requests at that level instead of waiting until they reach Apache.
Continue reading