Recent Blog Posts

Reverse-proxying a SOAP API accessed via PHP's SoapClient

I'm documenting this here, just because it's something I imagine I might have to do again someday... and when I do, I want to save myself hours of pain and misdirection.

A client had an old SOAP web service that used IP address whitelisting to authenticate/allow requests. The new PHP infrastructure was built using Docker containers and auto-scaling AWS instances. Because of this, we had a problem: a request could come from one of millions of different IP addresses, since the auto-scaling instances use a pool of millions of AWS IP addresses in a wide array of IP ranges.

Because the client couldn't change their API provider (at least not in any reasonable time-frame), and we didn't want to throw away the ability to auto-scale, and also didn't want to try to build some sort of 'Elastic IP reservation system' so we could draw from a pool of known/reserved IP addresses, we had to find a way to get all our backend API SOAP requests to come from one IP address.

The solution? Reverse-proxy all requests to the backend SOAP API.

Apache, fastcgi, proxy_fcgi, and empty POST bodies with chunked transfer

I've been working on building a reproducible configuration for Drupal Photo Gallery, a project born out of this year's Acquia Build Hackathon.

We originally built the site on an Acquia Cloud CD environment, and this environment uses a pretty traditional LAMP stack. We didn't encounter any difficulty using AWS Lambda to post image data back to the Drupal site via Drupal's RESTful Web Services API.

The POST request is built in Node.js using:

Self-signed certificates via Ansible for local testing with Nginx

Most of my servers are using TLS certificates to encrypt all traffic over HTTPS. Since Let's Encrypt (and certbot) have taken the world of hosting HTTPS sites by storm (free is awesome!), I've been trying to make sure all my servers use the best settings possible to ensure private connections stay private. This often means setting up things like HSTS, which can make local / non-production test environments harder to manage.

Consider the following:

Photographing the 2017 Total Solar Eclipse

Last year, when I first learned that my house was in the path of totality for this year's eclipse, I immediately logged into BorrowLenses and rented a Nikon 200-500mm f/5.6 VR lens (for photography—it's now on my wishlist) and then purchased a set of eclipse glasses for my family, and materials to build a solar filter for the lens.

I've learned from Reddit's DIY community that people like the end result first... then an explanation, so:

2017 Total Solar Eclipse composite by Jeff Geerling
See the full-size image of the Eclipse composite on Flickr.

Slow Ansible playbook? Check ansible.cfg!

Today while I was running a particularly large Ansible playbook about the 15th time in a row, I was wondering why this playbook seemed to run quite a bit slower than most other playbooks, even though I was managing a server that was in the same datacenter as most of my other infrastructure.

I have had pipelining = True in my system /etc/ansible/ansible.cfg for ages, and initially wondered why the individual tasks were so delayed—even when doing something like running three lineinfile tasks on one config file. The only major difference in this slow playbook's configuration was that I had a local ansible.cfg file in the playbook, to override my global roles_path (I wanted the specific role versions for this playbook to be managed and stored local to the playbook).

So, my curiosity led me to a more thorough reading of Ansible's configuration documentation, specifically a section talking about Ansible configuration file precedence:

Get a list of all available images in the DigitalOcean v2 API

I frequently need to check the slug or id of a particular Droplet image (or in AWS parlance, an AMI) that I can use to launch new DigitalOcean droplets via Ansible. And seeing as tonight I had to search for 'how to get a list of all DigitalOcean images' about the hundredth time, I figured I'd publish this in a blog post so I can find it more easily in the future.

Without further ado:

curl -X GET --silent "" -H "Authorization: Bearer $DO_API_TOKEN"

This assumes you have exported a valid $DO_API_TOKEN previously. If not, just paste your DigitalOcean API token in place of $DO_API_TOKEN, and then run the command.

It dumps out a ton of JSON, so you can either paste it through something like, or try reading it in all it's unformatted glory. And if the latter, are you a robot?

Bonus trick: If you're on a Mac, you can add | pbcopy to the end of that command to have the output stuck into your clipboard, for easy pasting.


Subscribe to Jeff Geerling's Blog