Category Archives: General

WordPress Child Theme

Just under a year ago, I wrote about the changes I made to the WordPress TwentyTwelve theme to remove the comment RSS feeds from the site headers. As I was adding the new Microblog RSS feed to the header, I decided to see if I could migrate my modifications into a child theme.

The big advantage of creating a child theme, instead of modifying the parent (original) theme, is that when there is an update available to the parent theme your modifications won’t be lost.

My original modifications required changes to two files:

  1. functions.php:

    • Comment out the line that adds in all feeds:

      // add_theme_support( 'automatic-feed-links' );
      
    • Add in a filter to remove the post comment feeds:

      function disablePostCommentsFeedLink($for_comments) {
          return;
      }
      add_filter('post_comments_feed_link','disablePostCommentsFeedLink');
      
  2. header.php:

    • Added in links to the main RSS feed (since they were removed from functions.php).

To migrate the changes to a child theme, I reverted my version of the TwentyTwelve theme to its original state. You can find my child theme on Github, and you can see the torturous path I took to develop it in the commit history.

My first attempt involved duplicating the entire header.php file, with my changes, into the child theme, and I gave up on figuring out how to comment out add_theme_support( 'automatic-feed-links' ); from the child.

For the second attempt, I tried to achieve the commenting out of add_theme_support( 'automatic-feed-links' ); by removing the function calling it from the after_theme_setup hook. I struggled with figuring out what hook to attach the removal to, and consulted the Actions Run During a Typical Request list in the Codex. Ultimately I attached the removal function to the same after_theme_setup hook, but with a priority of 0:

add_action( 'after_setup_theme', 'child_remove_parent_function_twentytwelve_setup', 0 );

Once I had that working, I stumbled onto the feed_links_show_comments_feed filter, which greatly simplified the whole endeavor. The filter removes both the master comment feed and post comment feeds, which was my entire original objective. I was able to strike both the header.php file and the effort to comment out add_theme_support( 'automatic-feed-links' ); in functions.php.

I was able to accomplish the removal of the comment RSS feeds in my child theme with just this in my functions.php file1:

// disable comment feeds (this seems to disable main and post comment feeds)
add_filter( 'feed_links_show_comments_feed', '__return_false' );

The only thing left to do was add back in the Microblog RSS feed, which I injected into the wp_head hook2 (this, too, is in functions.php):

// Add in microblog feed to header
function microblog_feed() {
    echo '
<link rel="alternate" type="application/rss+xml" title="Jeff Vautin &raquo; Microblog Feed" href="/micro.xml" />
';
}
add_action('wp_head', 'microblog_feed');

I ended up with the same functionality I had before, but in just a handle of lines of code, nicely contained in a child theme. Feel free to fork it for your own use!


  1. Beyond the boilerplate needed to create a child theme

  2. I took inspiration from this Stack Overflow answer

Dakota Access Pipeline

The Army Corps of Engineers is accepting public comments on their plan to grant the easement required to complete the Dakota Access Pipeline. The Notice of Intent indicates that the public comment period runs through February 20, 2017. Comments can be sent to Mr. Gib Owen.

I used a few minutes of this snowy, lazy morning to send the following feedback:

Mr. Owen,

I’m writing to request that Dakota Access, LLC, NOT be granted an easement to cross Lake Oahe.

Because the proposed easement is only one half-mile upstream from the Standing Rock Sioux Tribe’s reservation, any spill would have a substantial impact on their land. As we have seen already in 2017, these pipelines have a substantial likelihood of leaking, and tremendous capacity for damage when a leak occurs. The following articles support this claim:

Report: Kinder Morgan’s pipeline spill in South Carolina bigger than estimated http://savannahnow.com/news/2017-02-03/report-kinder-morgans-pipeline-spill-south-carolina-bigger-estimated This article details a gasoline pipeline spill of more than 500,000 galloons, still seeping into creeks in South Carolina.

Iowa oil spill underscores pipeline risks day after Trump revives major projects https://www.theguardian.com/environment/2017/jan/25/oil-spill-iowa-trump-keystone-dakota-access-pipeline An oil pipeline has leaked 138,600 gallons in Iowa in January.

Oil Pipeline Spills 53,000 Gallons on First Nations Land http://www.ecowatch.com/oil-pipeline-spill-first-nations-2211497739.html Also in January, a Canadian pipeline leaked 200,000L of oil onto Native American lands.

These articles highlight the inability to guarantee the integrity of these pipelines. I urge the Army Corps of Engineers to seek an alternative location for the Dakota Access pipeline.

Thank you,

Jeff Vautin

<Address>
<Phone>
<Email>

Please consider submitting a comment!

Microblog Feed

Following advice from Manton, I’m configuring a new microblog feed on this site. I’d like to own my content, so I want my micro posts to originate here and then mirror over to Twitter.

Per Manton’s recommendations, I’m configuring these micro posts as a Status format, without titles, and in their own category — Micro.

I modified the site’s .htaccess file so that the current RSS feed excludes posts from the Micro category, and to create a Micro feed with only posts from this category. To do this, I changed /var/www/jeffvautin.com/.htaccess from:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

To:

# BEGIN micro
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteRule ^rss\.xml$ "/feed?cat=-104"[L,R]
RewriteRule ^micro\.xml$ "/feed?cat=104"[L,R]
RewriteCond %{Query_STRING} ^$
RewriteRule ^feed/?$ "/rss.xml" [L,R]
</IfModule>
# END micro

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

Where 104 is the category ID for the Micro category. I copied most of this from the discussion on the gist Manton provided, with one modification: I added /? (optional trailing slash) to the following line, so that either https://jeffvautin.com/feed or https://jeffvautin.com/feed/ would find the micro-less feed:

RewriteRule ^feed/?$ "/rss.xml" [L,R]

I found good resources regarding the .htaccess file from Digital Ocean:

Next, I created an IFTTT rule to watch for posts in the Micro feed and to put the post content in a tweet.

I still want to setup a simple posting method from my iPhone, likely using Workflow. I also want to clean up the site’s appearance — I Status posts have a bit of extra cruft displayed that I could clean up, and the Recent Posts widget displays title-less posts by their post ID, which is unsightly.

Amazon & Breitbart

As of this morning, Amazon is still choosing to advertise on Breitbart.com. This is disheartening, and I’m planning to boycott Amazon until this policy changes1:

Telling Amazon how you feel is really easy. You can go to their feedback form to leave a comment. This is what I wrote:

As a longtime, frequent, customer, I’m very disheartened by Amazon’s decision to continue advertising on Breitbart.com, a white- supremacist propaganda website. Please reconsider, and remove your ads from Breitbart.com. Until then, I’ll be reducing the amount of business I do with you.

My call to action (cribbed from Beau Willimon) is exploding this morning, with ~50 retweets in the first 20 minutes:


  1. Even if it means leaving the house to go shopping! 

Private VPN with macOS Server

After being inspired by Dan Moren1 a long time ago, I finally went to the trouble of configuring a personal VPN, with macOS Server and my always-on iMac.

The first part was to configure a domain name with dynamic DNS, to point at my home network. I used ChangeiP to create a free domain name for this purpose. To transmit my current IP address to ChangeiP (and to OpenDNS), I purchased IP Monitor from the Mac App Store.

The second part was configuring the VPN service in macOS Server. I’m listing the steps here, but I wouldn’t have figured this all out without Todd Olthoff’s YouTube series on El Capitan Server. Here we go:

  1. In the server Overview panel, I edited the Host Name to match the DDNS domain name I configured with ChangeiP. This involved switching from a .local name to an ‘Internet’ name (the domain name), so the server is accessable from the broader internet.
  2. Then in the VPN panel, I set the ‘VPN Host Name’ to match the domain name.
  3. I generated a ‘Shared Secret’ using 1Password.
  4. I configured the client address range for IP addresses beyond our router’s dynamic set, and beyond the few static IPs I’ve set up.
  5. I pointed the DNS Settings to point to our Time Capsule (which is where all machines on the network go for DNS).
  6. I turned the service on.

I had initially let Server configure DNS for me, but disabling it hasn’t negatively impacted anything, so I’m leaving it off for now.

The only thing left to do was to set up the client devices. On the Mac:

  1. Open Network Preferences, and hit the ‘+’ button to add a new service.
  2. Select VPN from the drop down, and set the VPN Type to ‘L2TP over IPSec’.
  3. Set the server address to the domain name.
  4. Set the account name to your account (as configured in the ‘Users’ panel of the Server app).
  5. Open Authentication Settings and enter your account password, as well as the Shared Secret.
  6. In Advanced…, I selected ‘Send all traffic over VPN connection’.

The process is very similar on iOS; you can access it from Settings -> General -> VPN.


  1. Dan pointed to some Macminicolo instructions that I found very intimidating - I think most of the steps they outline are really only necessary if you’re hosting your server in a datacenter like theirs. 

Bose SoundTouch and HomeKit

I had so much fun with my previous HomeBridge adventure that I went looking for additional plug-ins I could add. I found the HomeBridge SoundTouch plugin, and installing it could not have been easier.

First, I killed the homebridge process:

launchctl unload ~/Library/LaunchAgents/com.homebridge.server.plist

Then, I downloaded the plugin:

sudo npm install -g homebridge-soundtouch

Finally, I had to modify my config.json file (~/.homebridge/config.json). I included this before the final }:

"accessories": [
        {
            "accessory": "SoundTouch",
            "name": "Kitchen Speaker",
            "room": "Kitchen"
        }
    ]

(Kitchen is the name of the speaker as configured in the Soundtouch app, and Kitchen Speaker is how I want it to appear in HomeKit. The word speaker may seem redundant, but it’s useful, since HomeKit doesn’t actually know it’s a speaker — it just thinks it’s a dumb switch.)

Finally, I restarted the homebridge process:

launchctl load ~/Library/LaunchAgents/com.homebridge.server.plist

Chamberlain MyQ and HomeBridge

Evan at 40tech.com wrote up instructions for configuring the Chamberlain MyQ system with HomeKit. Since Chamberlain still hasn’t released official support for HomeKit, you can use HomeBridge as an intermediary between iOS and the official Chamberlain API. Homebridge requires a computer (or Raspberry Pi) to be running on your home network; in my case, my always-on iMac fits the bill.

Homebridge is fairly easy to setup, especially if you already have Homebrew and Node.js on your computer. I ran into a few issues with my Homebrew installation after the upgrade to Sierra, so I decided to start with a fresh install.

Installing Homebrew and Node.js

You can follow the instructions here to install Homebrew. The basic installation command is:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

This guide suggests adding the Homebrew location to your ~/.bash_profile, and I found that helpful for the Node installation:

export PATH="/usr/local/bin:$PATH"

With Homebrew, you can now install node:

brew install node

Installing HomeBridge

Node brings with it npm, the Node Package Manager. You can use this to install HomeBridge and the LiftMaster2 plugin:

sudo npm install -g homebridge
sudo npm install -g git+https://github.com/luisiam/homebridge-liftmaster2.git

If you see warnings, you can try adding the flag –unsafe-perm to each npm call above. I believe having the Homebrew location on the path prevented me from seeing any warnings, but I’m not sure.

You can now try running HomeBridge:

homebridge

It should start up, and you’ll see a message about not having a configuration file installed. It will look for the file here:

nano ~/.homebridge/config.json

Evan provided his configuration file contents:

{
"bridge": {
"name": "Homebridge",
"username": "CC:22:3D:E3:CE:30",
"port": 51826,
"pin": "031-45-154"

},

"description": "JSON API",
"platforms": [{
"platform": "LiftMaster2",
"username": "me@email.com",
"password": "password"
}]
}

You’ll need to replace the username and password in the config.json file with your MyQ credentials. You can now try running homebridge again, and you should see a successful connection! You can add the bridge to the HomeKit database on your phone through the Home app.

Configuring launchd to Keep HomeBridge Alive

If you want to make sure HomeBridge is always running on your Mac, you can use these instructions to configure a Launch Agent.

You’ll need to create a plist file for the agent; I saved mine as ~/Library/LaunchAgents/com.homebridge.server.plist. The file contents should be:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>com.homebridge.server</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/homebridge</string>
        <string>-I</string>
    </array>
    <key>EnvironmentVariables</key>
    <dict>
            <key>PATH</key>
            <string>/usr/local/bin/:$PATH</string>
    </dict>
</dict>
</plist>

This will start HomeBridge when your computer boots, and restart it if it dies. To manually start the process:

launchctl load ~/Library/LaunchAgents/com.homebridge.server.plist

And to stop it:

launchctl unload ~/Library/LaunchAgents/com.homebridge.server.plist

Next…

Now HomeBridge should be up and running, and you should be able to control your MyQ devices from Siri and Home on iOS. Next up, I want to tackle adding HomeKit support for my Nest devices.

iptables & fail2ban

This site has been seeing some downtime recently, and I’ve been learning a little about hardening a server.

The first symptom of the problem was an intermittent “Error Establishing Database Connection” message when trying to load a page. Restarting mysql would do the trick:

sudo service mysql start

But it would keep going down — sometimes after a month, sometimes after 20 minutes. Server Fault guided me to apache, and the possibility that apache was consuming so much memory that mysql was getting killed off by the OS. I found a script to help monitor the behavior of apache:

while true; do ps auxfww | grep apache | grep -v -e cronolog -e grep | awk '{ vsum+=$5; rsum+=$6 } END { print "VSZ:", vsum, "(", vsum/NR, ") RSS:", rsum, "(", rsum/NR, ") Procs:", NR }'; sleep 5; done;

This lead me to check out the apache logs (via sudo cat /var/log/apache2/access.log):

163.172.176.64 - - [28/Aug/2016:12:33:32 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:32 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:32 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:32 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:32 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.174.28 - - [28/Aug/2016:12:33:33 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:33 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.174.28 - - [28/Aug/2016:12:33:33 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.176.64 - - [28/Aug/2016:12:33:33 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.176.64 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.174.28 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.176.64 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.174.28 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.176.64 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"
163.172.177.210 - - [28/Aug/2016:12:33:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 596 "-" "Googlebot/2.1 (+http://www.google.com/bot.html)"

It seemed odd that the Googlebot was hitting the server so often, and trying to POST to /xmlrpc.php.1 Some searching led me to the use of iptables to just directly block these IP addresses, since they’re probably just trying to spam my database. So I checked my current iptables rules:

sudo iptables -L

But I received an access denied message. A little more searching led me to the possibility that when I had updated my VPS’ operating system, its kernal was possibly out of step with Digital Ocean’s settings. So I reinstalled the kernal:

sudo apt-get install --reinstall linux-image-4.2.0-25-generic

At that point I was able to review the iptables rules. To get a list of IP addresses to ban, I used this command:

sudo grep xmlrpc /var/log/apache2/access.log | cut -d' ' -f1 | sort | uniq -c | sort -rn | head -n26

And I got the following list:

73257 163.172.176.64
70151 163.172.174.28
53242 163.172.177.210
49839 163.172.180.159
35499 163.172.148.152
31605 163.172.167.37
29711 163.172.132.17
27755 163.172.167.174
26929 163.172.179.115
25984 212.47.248.17
25816 163.172.155.237
25536 163.172.132.42
24879 163.172.154.114
20752 163.172.158.253
15008 163.172.179.147
13471 212.47.243.235
13133 163.172.177.30
11662 163.172.179.127
  921 163.172.179.90
  903 163.172.171.182
  815 163.172.149.145
  765 163.172.169.151
  576 37.1.213.195
  541 163.172.141.248
  252 185.106.122.248
  126 163.172.159.56

To add those IPs to the list of rules for iptables, I ran this command:

for ip in $(sudo grep xmlrpc /var/log/apache2/access.log | cut -d' ' -f1 | sort | uniq -c | sort -rn | head -n26 | awk '{print $2}'); do sudo iptables -I INPUT 1 -s $ip -j DROP; done

And confirmed those were added to the rules with:

sudo iptables -S

To persist these rules across reboots of the machine, I used iptables-persistent:

sudo apt-get update
sudo apt-get install iptables-persistent

Subsequent rule changes can be persisted by reconfiguring iptables-persistent:

sudo dpkg-reconfigure iptables-persistent

I also stumbled onto fail2ban, and the wordpress plugin WP fail2ban:

The tool Fail2ban is useful in preventing unauthorized access to both your Droplet and your WordPress site. It notes suspicious or repeated login failures and proactively bans those IPs by modifying firewall rules for your Droplet.

Digital Ocean has a great guide to setting up fail2ban to protect your wordpress install. Since fail2ban dynamically modifies the iptables rules, you’ll want to persist your rules while fail2ban is disabled:

sudo service fail2ban stop
sudo dpkg-reconfigure iptables-persistent
sudo service fail2ban start

Hopefully establishing this firewall will keep the site up more regularly.


  1. It would be reasonable to ask why I have xmlrpc access enabled. I’m using Dr. Drang’s WP-MD to post from BBEdit, and his tools rely on xmlrpc access. 

afclip

Apple provides a set of audio tools that you can use when you’re mastering music. In particular, the afclip utility is a fantastic analysis tool. You can use to make sure your tracks have enough headroom for a clean encoding in the iTunes Plus format.

To use afclip, first download it from Apple. Run the installer1. Then, open up a terminal window and type afclip FILENAME, where you replace FILENAME with the name of your file. If you don’t want to bother typing out the filename, you can just drag the file onto the terminal window.

When you run the utility, hopefully you’ll just see some text that indicates everything is fine with your file:

afclip : "01_Room_5.17.16.wav"    2 ch,  44100 Hz, 'lpcm' (0x0000000C) 16-bit little-endian signed integer
 -- no samples clipped --

But you may see more detail:

afclip : "06_Wall_5.17.16.wav"    2 ch,  44100 Hz, 'lpcm' (0x0000000C) 16-bit little-endian signed integer
CLIPPED SAMPLES:
    SECONDS          SAMPLE    CHAN    VALUE        DECIBELS
   57.385431       2530697.50    1    -1.006987     0.060476
   65.400034       2884141.50    1    -1.001764     0.015309
  195.992483       8643268.50    2     1.009248     0.079958
  198.687313       8762110.50    1     1.005957     0.051587
  214.678878       9467338.50    1     1.002328     0.020199
  222.696179       9820901.50    1     1.001868     0.016213
  234.043322      10321310.50    1     1.001779     0.015437

   total clipped samples    Left   on-sample:        0    inter-sample:        6
   total clipped samples    Right  on-sample:        0    inter-sample:        1

This indicates that this song would clip in seven places when played back. Interestingly, all of the clips are identified as ‘inter-sample’. This means the waveform exceeds 0dBFS between the samples that are actually present in the file. Inter-sample peaks are often the result of using a non-oversampling brick-wall limiter, such as the Waves L1. These limiters ensure that every sample is below the threshold you set, but they don’t make any promises about the waveform between samples.

In this case, we can fix the issue by just attenuating the track by 0.08dB, which should be inaudible. It could be much worse — in theory, there’s no limit to how large your inter-sample peaks can be. In practice, they’re often less than 2dB.

Inter-sample peaks matter for (at least) two reasons:

  1. When the tracks are played back through a digital-to-analog converter (DAC), the analog signal may clip if the DAC wasn’t designed to provide headroom for inter-sample peaks. This is less of a problem on expensive playback equipment.

  2. Inter-sample peaks can cause distortion when the tracks are being encoded to lossy formats such as MP3 or AAC. Since this is the main way people are getting their music these days, it’s really important to check for this!


  1. Ironically, the installer fails the Gatekeeper check because it is “from an unidentified developer”.