So your Google WiFi pucks have the slows

The short version of this post is that the “Preferred activities” feature in the Google Home app may have undesired results, and before tearing your hair out try turning it off to see if things improve. Read on for discussion.

The problem

I live a row house and, as it typical of row houses in the Northeast United States, it’s tall and deep, rather than wide. This always posed a problem for WiFi coverage–the router is in the front of the house where the cable comes in from the street, so by the time you reach the kitchen in the rear of the house, to say nothing of the second and third floors, the signal became weak or non-existent.

Read More

Multiple PHP versions under the same domain

I recently had cause to run two different versions of PHP under the same top-level domain. I was able to accomplish this using Apache and PHP-FPM, leveraging Apache’s Directory directive. This builds on DigitalOcean’s excellent tutorial, “How To Run Multiple PHP Versions on One Server Using Apache and PHP-FPM on Ubuntu 18.04”, and assumes that you have done something similar to get multiple versions of PHP running using PHP-FPM.

In my use case, I have multiple different version of Moodle running under the same top-level domain. Each Moodle version is installed in a different directory under that domain, and has its own uploads and database. Moodle is somewhat aggressive about supported PHP versions, and I needed to have both PHP 7.4 (for Moodle 3.9) and PHP 8.0 (for Moodle 4.1) available, and each cannot run under the other version.

The solution is to add an Directory override for the site that needs the lower version of PHP, while leaving the higher version as the default case:

Read More

Browser Headers and WordPress

We’ve been running WordPress using Cloudfront as a full-site front-end cache with a low TTL and it’s been great overall, but one pain point has been which headers to whitelist in the origin configuration. This is pretty important: origin behavior governs what data Cloudfront passes back to the actual containers (or EC2 instances, it doesn’t matter in this case) serving your WordPress site. Omitting the wrong headers can have some fairly drastic consequences, like rich-text editors not displaying or REST API calls failing. This post takes Cloudfront as its example, but this would be relevant with any solution where you’re defining an allowlist of headers instead of just passing everything.

Behaviors

Before tackling headers, let me say a few words about behaviors in Cloudfront. Carl Alexander does a great job on this in How to use CloudFront to do WordPress page caching. For each behavior in Cloudfront you can define a different origin (e.g. Fargate containers, an S3 bucket, a Lambda function), which HTTP methods to allow, which headers to allow, what the caching policy should be. You differentiate behaviors by path. In a WordPress install, that means you could define different behaviors for each of the following paths:

Read More

Proxying Cloudfront with Nginx

Don’t do this.

You’re still here? Cool, let’s continue. For complicated reasons involving a legacy on-premises application I had a static site on AWS that I needed to route to with an Nginx reverse proxy. The application architecture included several locations, each of which was proxied to a different port on an on-premises server. The landing page, and only the landing page (and its assets), are on Cloudfront. For historical reasons, I needed to have this entire collection under a single DNS name.

Location, location …

Read More

EFS mount watchdog and CPU usage

The moral of today’s story is that there is a direct relationship between the number of EFS mounts on an EC2 instance and the resting level of CPU usage.

We ship our Fargate deployments with a bastion host if they contain an EFS filesystem and/or an RDS cluster. This takes the form of an EC2 autoscaling group. As we only need the bastion host for time-limited tasks, we keep the desired capacity at 0 by default and raise to 1 as needed. We use the scaling policies to ensure that the instance is turned down after a period of inactivity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const bastionCPUThreshold = opts.cpuThreshold ?? 1;
const bastionScalingPeriod = opts.scalingPeriod ?? Duration.minutes(30);

const CPUUtilizationMetric = new Metric({
namespace: 'AWS/EC2',
metricName: 'CPUUtilization',
dimensionsMap: {
AutoScalingGroupName: this.autoScalingGroup.autoScalingGroupName,
},
period: bastionScalingPeriod,
});

const scalingPolicy = this.autoScalingGroup.scaleOnMetric('ScaleToCPU', {
metric: CPUUtilizationMetric,
scalingSteps: [
{ upper: bastionCPUThreshold, change: 0 },
{ lower: bastionCPUThreshold, change: 1 }
],
adjustmentType: AdjustmentType.EXACT_CAPACITY,
});

Read More

Customizing the CDK bootstrap stack

Amazon’s CDK creates a helper Cloudformation stack (by default named CDKToolkit) with a few resources to assist with deployment. The most familiar to regular users are the S3 asset bucket and the ECR repository.

A source of mild frustration for my colleagues and me is that this default stack doesn’t set lifecycle policies on either, which then trips up Amazon’s security controls (S3 10 and ECR 3, respectively).

Fortunately, there is a relatively straightforward solution, and that’s customizing the Cloudformation template that manages the CDKToolkit stack. I hadn’t realized before now that you can do this but it’s well-documented. First, use cdk bootstrap to output the contents of the template. You’ll want to ensure that you’re using the same version of CDK that you’ll use to deploy the stack:

Read More

Moodle, TypeScript, and CDK

We moved our Moodle workloads to AWS in 2020, using CDK to manage the infrastructure. It’s one of our oldest such deployments and has been stable for years. I was nonplussed, to say the least, when, I attempted to update our development environment to the Moodle 4.1 beta and received almost 400 TypeScript errors like the one below:

1
public/lib/editor/tiny/js/tinymce/tinymce.d.ts(7,10): error TS2304: Cannot find name 'Range'.

It took me a few minutes to realize what I was actually looking at. We install the Moodle core code in the public directory of the project. CDK’s npm run build command wraps tsc, the typescript compiler, and it was looking at TypeScript modules inside the Moodle directory. Thanks to a helpful hint from Stackoverflow, I modified tsconfig.json to exclude public:

Read More

Octopussy

Octopussy may have the most ludicrous plot for a James Bond movie, and that’s saying something. We’ve had two where the villain launched a laser satellite (Diamonds are Forever and Die Another Day). In A View to a Kill, Christopher Walken planned to cause an earthquake to destroy Silicon Valley. You Only Live Twice (scripted by Roald Dahl!) has a spaceship that eats other spaceships. This was retooled in The Spy Who Loved Me with a supertanker that eats submarines. We haven’t even mentioned Moonraker, in which James Bond actually goes to outer space!

Tongue firmly planted in cheek, this describes the plot of Octopussy: “a circus clown foils an attempt by a deposed Afghan prince and rogue Russian general to destroy a circus with a nuclear bomb.” This doesn’t even touch on the titular jewel smuggler who established an all-female smuggling ring organized around the “Octopus cult.”

Octopussy usually rates in the bottom third of Bond movies, though without the rancor surrounding The Man with the Golden Gun, A View to a Kill, or Die Another Day. The elegaic tone, which starts with Rita Coolidge’s theme “All Time High”, accounts for some of this. Moore was clearly too old, and casting a returning Maud Adams against him eliminated some of the icky sexual politics from the previous film For Your Eyes Only. The action sequence surrounding the train crossing the German border is well-done, despite its inherent implausibility. Douglas Wilmer is fun in a small role as an art expert. Kabir Bedi has memorable turn as monster heel Gobinda.

Read More

The Forgotten Workers of Isla Nublar

When Michael Crichton wrote Jurassic Park he employed the conceit that this was a reconstructed history, based on interviews with the survivors and drawing on various reports. He used this technique in other works such as The Andromeda Strain and Congo (and abandoned it for Sphere and Timeline).

In-universe, the book is at pains to emphasize the small number of people on Isla Nublar. In the introduction, Crichton writes that “fewer than twenty people [witnessed the events]” and that “only a handful survived.” The movie goes even further; all the non-essential personnel leave the island on the boat, leaving the VIPs to fend for themselves. From a Watsonian standpoint, this is ludicrous. Much like the letters of transit in Casablanca, Spielberg rightly figures that no one will challenge it if he keeps things rolling again. The Doylist explanation is that Spielberg wasn’t making an R-rated movie and wanted to limit the on-screen carnage (to a point).

Spielberg was also perhaps addressing a textual anomaly in the source material. Contrary to Crichton’s assertions about the limited number of people on the island, I can demonstrate that the minimum number of people on the island is forty. The Doylist explanation is that he lost count. That’s boring and we’re not doing that. The Watsonian explanation is for more sinister: the as-yet untold story of Jurassic Park is the wholesale slaughter of dozens of support personnel. Below I will count the number of people on the island. Page references are to the standard paperback. Bolded numbers are the character count.

Read More

Amtrak Olympics

Folks, I’ve traveled more than 100,000 miles on Amtrak and I’ve seen some strange stuff. To celebrate those journeys, and in the spirit of Steve Bull’s seminal “Winter Games From the Dark Side” article in the Country Journal, I’ve developed twelve “events” that Amtrak passengers could participate in. Every one of these events is grounded in personal experience. Note that for any of these events forcible removal from the train by Amtrak staff is grounds for immediate disqualification.

1. Havre Challenge

The Empire Builder makes a daily stop in Havre, Montana. It’s a longish stop; besides a separate refueling, there’s a crew change and restocking from the commissary. The station is located on Main Street, just one block from US-2 and within Havre’s central business district. Enterprising passengers may attempt to patronize those businesses without getting left behind. Points will be awarded for money won in any of the casinos, for drinks consumed at Shamrock’s, or takeout meals presented to the on-board train staff. Any passenger who returns to the train with an ATV purchased at Hi-Line Polaris wins an automatic victory and the ATV will be stored in the baggage car. No points are awarded if the passenger is left behind in Havre. We recommend the Quality Inn, it’s about half a mile down the road.

Read More