The Pitch Wouldn't it be great if there was a simple way to send a notification to your phone(s) with just a curl call? Then you could get notified when a script completes, a server reboots, a user logs in to a system, or a sensor connected to Home Assistant changes state. How great would that be??
ntfy.sh (pronounced notify) provides just that. It's an open-source, easy-to-use, HTTP-based notification service, and it can notify using mobile apps for Android (Play or F-Droid) or iOS (App Store) or a web app.
1cp -a virtuallypotato.com runtimeterror.dev 2rm -rf virtuallypotato.com 3ln -s virtuallypotato.com runtimeterror.dev If you've noticed that things look a bit different around here, you might also have noticed that my posts about VMware products had become less and less frequent over the past year or so. That wasn't intentional, but a side-effect of some shifting priorities with a new position at work. I'm no longer on the team responsible for our VMware environment and am now more focused on cloud-native technologies and open-source DevOps solutions.
I spend a lot of my time and energy answering technical questions, both professionally and "for fun" as a way to scratch that troubleshooting itch. How a question is asked plays a big factor in how effectively I'll be able to answer it.
Years ago I came across Eric Steven Raymond's How To Ask Questions The Smart Way and it really resonated with me. I wish everyone would read it before asking for technical help but I recognize it's a pretty large doc so that's an unrealistic wish.
It's super handy when a Linux config file is loaded with comments to tell you precisely how to configure the thing, but all those comments can really get in the way when you're trying to review the current configuration.
Next time, instead of scrolling through page after page of lengthy embedded explanations, just use:
1egrep -v "^\s*(#|$)" $filename For added usefulness, I alias this command to ccat (which my brain interprets as "commentless cat") in my ~/.
I've lately been trying to do more with Salt at work, but I'm still very much a novice with that tool. I thought it would be great to have a nice little portable lab environment where I could deploy a few lightweight VMs and practice managing them with Salt - without impacting any systems that are actually being used for anything. Along the way, I figured I'd leverage HashiCorp Vagrant to create and manage the VMs, which would provide a declarative way to define what the VMs should look like.
Fix available
VMware has released a fix for this problem in the form of ESXi 7.0 Update 3k:
If you already face the issue, after patching the host to ESXi 7.0 Update 3k, just power on the affected Windows Server 2022 VMs. After you patch a host to ESXi 7.0 Update 3k, you can migrate a running Windows Server 2022 VM from a host of version earlier than ESXi 7.
I've shared in the past about how I use custom search engines in Chrome as quick web shortcuts. And I may have mentioned my love for Tailscale a time or two as well. Well I recently learned of a way to combine these two passions: Tailscale golink. The golink announcement post on the Tailscale blog offers a great overview of the service:
Using golink, you can create and share simple go/name links for commonly accessed websites, so that anyone in your network can access them no matter the device they’re on — without requiring browser extensions or fiddling with DNS settings.
You might remember that I'm a pretty big fan of Tailscale, which makes it easy to connect your various devices together in a secure tailnet, or private network. Tailscale is super simple to set up on most platforms, but you'll need to install it manually if there isn't a prebuilt package for your system.
Here's a condensed list of the steps that I took to manually install Tailscale on VMware's Photon OS, though the same (or similar) steps should also work on just about any other systemd-based system.
I've been leveraging the open-source Tanzu Community Edition Kubernetes distribution for a little while now, both in my home lab and at work, so I was disappointed to learn that VMware was abandoning the project. TCE had been a pretty good fit for my needs, and now I needed to search for a replacement. VMware is offering a free version of Tanzu Kubernetes Grid as a replacement, but it comes with a license solely for non-commercial use so I wouldn't be able to use it at work.
You may have heard that there's a new vSphere release out in the wild - vSphere 8, which just reached Initial Availability this week. Upgrading the vCenter in my single-host homelab is a very straightforward task, and using the included Lifecycle Manager would make quick work of patching a cluster of hosts... but things get a little trickier with a single host. I could write the installer ISO to a USB drive, boot the host off of that, and go through the install interactively, but what if physical access to the host is kind of inconvenient?
VMware vCenter does wonders for abstracting away the layers of complexity involved in managing a large virtual infrastructure, but when something goes wrong it can be challenging to find exactly where the problem lies. And it can be even harder to proactively address potential issues before they occur.
Fortunately there's a super-handy utility which can making diagnosing vCenter significantly easier, and it comes in the form of the vSphere Diagnostic Tool Fling.
Way back in 2020, VMware released vSphere 7 Update 1 and introduced the new vSphere Clustering Services (vCLS) to improve how cluster services like the Distributed Resource Scheduler (DRS) operate. vCLS deploys lightweight agent VMs directly on the cluster being managed, and those VMs provide a decoupled and distributed control plane to offload some of the management responsibilities from the vCenter server.
That's very cool, particularly in large continent-spanning environments or those which reach into multiple clouds, but it may not make sense to add those additional workloads in resource-constrained homelabs1.
I recently started using Obsidian for keeping notes, tracking projects, and just generally organizing all the information that would otherwise pass into my brain and then fall out the other side. Unlike other similar solutions which operate entirely in The Cloud, Obsidian works with Markdown files stored in a local folder1, which I find to be very attractive. Not only will this allow me to easily transfer my notes between apps if I find something I like better than Obsidian, but it also opens the door to using git to easily back up all this important information.
I've been doing a bit of work lately to make my vRealize Automation setup more flexible and dynamic and less dependent upon hardcoded values. To that end, I thought it was probably about time to learn how to interact with the vRA REST API. I wrote this post to share what I've learned and give a quick crash course on how to start doing things with the API.
Exploration Toolkit Swagger It can be difficult to figure out where to start when learning a new API.
ESXi-ARM Fling v1.10 Update
On July 20, 2022, VMware released a major update for the ESXi-ARM Fling. Among other fixes and improvements, this version enables in-place ESXi upgrades and adds support for the Quartz64's on-board NIC. To update, I:
Wrote the new ISO installer to another USB drive. Attached the installer drive to the USB hub, next to the existing ESXi drive. Booted the installer and selected to upgrade ESXi on the existing device.
We've been working lately to use HashiCorp Packer to standardize and automate our VM template builds, and we found a need to pull in all of the contents of a specific directory on an internal web server. This would be pretty simple for Linux systems using wget -r, but we needed to find another solution for our Windows builds.
A coworker and I cobbled together a quick PowerShell solution which will download the files within a specified web URL to a designated directory (without recreating the nested folder structure):
Not long ago, I deployed a Tanzu Community Edition Kubernetes cluster in my homelab, and then I fumbled through figuring out how to log into it from a different device than the one I'd used for deploying the cluster from the tanzu cli. That setup works great for playing with Kubernetes in my homelab but I'd love to do some Kubernetes with my team at work and I really need the ability to authenticate multiple users with domain credentials for that.
Now that VMware has released vCenter 7.0U3c to resolve the Log4Shell vulnerabilities I thought it might be fun to run a security scan against the upgraded VCSA in my homelab to see how it looks. Of course, I don't actually have a security scanner in that environment so I'll need to deploy one.
I start off by heading to tenable.com/products/nessus/nessus-essentials to register for a (free!) license key which will let me scan up to 16 hosts.
I recently wrote about getting started with VMware's Tanzu Community Edition and deploying phpIPAM as my first real-world Kubernetes workload. Well I've spent much of my time since then working on a script which would help to populate my phpIPAM instance with a list of networks to monitor.
Planning and Exporting The first step in making this work was to figure out which networks I wanted to import. We've got hundreds of different networks in use across our production vSphere environments.
When I set up my Tanzu Community Edition environment, I did so from a Linux VM since the containerized Linux environment on my Chromebook doesn't support the kind bootstrap cluster used for the deployment. But now that the Kubernetes cluster is up and running, I'd like to be able to connect to it directly without the aid of a jumpbox. How do I get the appropriate cluster configuration over to my Chromebook?
Lately I've been spending some time getting more familiar with VMware's Tanzu Community Edition Kubernetes distribution, but I'm still not quite familiar enough with the tanzu command line. If only there were a better way for me to discover the available commands for a given context and help me type them correctly...
Oh, but there is! You see, one of the available Tanzu commands is tanzu completion [shell], which will spit out the necessary code to generate handy context-based auto-completions appropriate for the shell of your choosing (provided that you choose either bash or zsh, that is).
I recently needed to export a list of all the Linux VMs in a rather large vSphere environment spanning multiple vCenters (and the entire globe), and I wanted to include information about which virtual datacenter each VM lived in to make it easier to map VMs to their physical location.
I've got a Connect-vCenters function that I use to quickly log into multiple vCenters at once. That then enables me to run a single query across the entire landscape - but what query?
Back in October, VMware announced Tanzu Community Edition as way to provide "a full-featured, easy-to-manage Kubernetes platform that’s perfect for users and learners alike." TCE bundles a bunch of open-source components together in a modular, "batteries included but swappable" way: I've been meaning to brush up on my Kubernetes skills so I thought deploying and using TCE in my self-contained homelab would be a fun and rewarding learning exercise - and it was!
Not all that long ago, I shared about a somewhat-complicated WireGuard VPN setup that I had started using to replace my previous OpenVPN solution. I raved about WireGuard's speed, security, and flexible (if complex) Cryptokey Routing, but adding and managing peers with WireGuard is a fairly manual (and tedious) process. And while I thought I was pretty clever for using a WireGuard peer in GCP to maintain a secure tunnel into my home network without having to punch holes through my firewall, routing all my traffic through The Cloud wasn't really optimal1.
Non-technical users deserve private communications, too.
I shared a few months back about the steps I took to deploy my own Matrix homeserver instance, and I've happily been using the Element client for secure end-to-end encrypted chats with a small group of my technically-inclined friends. Being able to have private conversations without having to trust a single larger provider (unlike like Signal or WhatsApp) is pretty great. Of course, many Matrix users just create accounts directly on the matrix.
In case you missed the news, I recently migrated this blog from a site built with Jekyll to one built with Hugo. One of Hugo's cool features is the concept of Page Bundles, which bundle a page's resources together in one place instead of scattering them all over the place.
Let me illustrate this real quick-like. Focusing only on the content-generating portions of a Hugo site directory might look something like this:
Oops, I did it again.
It wasn't all that long ago that I migrated this blog from Hashnode to a Jekyll site published via GitHub Pages. Well, a few weeks ago I learned a bit about another static site generator called Hugo, and I just had to give it a try. And I came away from my little experiment quite impressed!
While Jekyll is built on Ruby and requires you to install and manage a Ruby environment before being able to use it to generate a site, Hugo is built on Go and requires nothing more than the hugo binary.
I've been wanting to learn a bit more about SaltStack Config so I recently deployed SSC 8.6 to my environment (using vRealize Suite Lifecycle Manager to do so as described here). I selected the option to integrate with my pre-existing vRA and vIDM instances so that I wouldn't have to manage authentication directly since I recall that the LDAP authentication piece was a little clumsy the last time I tried it.
For a while now, I've been using an OpenVPN Access Server virtual appliance for remotely accessing my homelab. That's worked fine but it comes with a lot of overhead. It also requires maintaining an SSL certificate and forwarding three ports through my home router, in addition to managing a fairly complex software package and configurations. The free version of the OpenVPN server also only supports a maximum of two simultaneous connections.
Thus far in my vRealize Automation project, I've primarily been handing the payload over to vRealize Orchestrator to do the heavy lifting on the back end. This approach works really well for complex multi-part workflows (like when generating unique hostnames), but it may be overkill for more linear tasks (such as just running some simple commands inside of a deployed guest OS). In this post, I'll explore how I use vRA Action Based eXtensibility (ABX) to do just that.
This is going to be a pretty quick recap of the steps I recently took to convert a single-node instance of vRealize Automation 8.4.2 into a 3-node High-Availability vRA cluster behind a standalone NSX Advanced Load Balancer (without NSX being deployed in the environment). No screenshots or specific details since I ran through this in the lab at work and didn't capture anything along the way, and my poor NUC homelab struggles enough to run a single instance of memory-hogging vRA.
Intro I've been using short.io with a custom domain to keep track of and share messy links for a few months now. That approach has worked very well, but it's also seriously overkill for my needs. I don't need (nor want) tracking metrics to know anything about when those links get clicked, and short.io doesn't provide an easy way to turn that off. I was casually looking for a lighter self-hosted alternative today when I stumbled upon a serverless alternative: sheets-url-shortener.
One of the requirements for my vRA deployments is the ability to automatically create a static A records for non-domain-joined systems so that users can connect without needing to know the IP address. The organization uses Microsoft DNS servers to provide resolution on the internal domain. At first glance, this shouldn't be too much of a problem: vRealize Orchestrator 8.x can run PowerShell scripts, and PowerShell can use the Add-DnsServerResourceRecord cmdlet to create the needed records.
I recently migrated this site from Hashnode to GitHub Pages, and I'm really getting into the flexibility and control that managing the content through Jekyll provides. So, naturally, after finalizing the move I got to work recreating Hashnode's "Series" feature, which lets you group posts together and highlight them as a collection. One of the things I liked about the Series setup was that I could control the order of the collected posts: my posts about building out the vRA environment in my homelab are probably best consumed in chronological order (oldest to newest) since the newer posts build upon the groundwork laid by the older ones, while posts about my other one-off projects could really be enjoyed in any order.
Connecting a deployed Windows VM to an Active Directory domain is pretty easy; just apply an appropriately-configured customization spec and vCenter will take care of it for you. Of course, you'll likely then need to move the newly-created computer object to the correct Organizational Unit so that it gets all the right policies and such.
Fortunately, vRA 8 supports adding an Active Directory integration to handle staging computer objects in a designated OU.
After a bit less than a year of hosting my little technical blog with Hashnode, I spent a few days migrating the content over to a new format hosted with GitHub Pages.
So long, Hashnode Hashnode served me well for the most part, but it was never really a great fit for me. Hashnode's focus is on developer content, and I'm not really a developer; I'm a sysadmin who occasionally develops solutions to solve my needs, but the code is never the end goal for me.
I'm preparing to migrate this blog thingy from Hashnode (which has been great!) to a GitHub Pages site with Jekyll so that I can write posts locally and then just do a git push to publish them - and get some more practice using git in the process. Of course, I've written some admittedly-great content here and I don't want to abandon that.
Hashnode helpfully automatically backs up my posts in Markdown format to a private GitHub repo so it was easy to clone those into a local working directory, but all the embedded images were still hosted on Hashnode:
I've heard a lot lately about how generous Oracle Cloud's free tier is, particularly when compared with the free offerings from other public cloud providers. Signing up for an account was fairly straight-forward, though I did have to wait a few hours for an actual human to call me on an actual telephone to verify my account. Once in, I thought it would be fun to try building my own Matrix homeserver to really benefit from the network's decentralized-but-federated model for secure end-to-end encrypted communications.
In past posts, I started by creating a basic deployment infrastructure in Cloud Assembly and using tags to group those resources. I then wrote an integration to let vRA8 use phpIPAM for static address assignments. I implemented a vRO workflow for generating unique VM names which fit an organization's established naming standard, and then extended the workflow to avoid any naming conflicts in Active Directory and DNS. And, finally, I created an intelligent provisioning request form in Service Broker to make it easy for users to get the servers they need.
I was recently introduced to AdGuard Home by way of its very slick Home Assistant Add-On. Compared to the relatively-complicated Pi-hole setup that I had implemented several months back, AdGuard Home was much simpler to deploy (particularly since I basically just had to click the "Install" button from the Home Assistant add-ons manage). It also has a more modern UI with options arranged more logically (to me, at least), and it just feels easier to use overall.
A few days ago, I shared how I combined a Service Broker Custom Form with a vRO action to automatically generate a unique and descriptive deployment name based on user inputs. That approach works fine but while testing some other components I realized that calling that action each time a user makes a selection isn't necessarily ideal. After a bit of experimentation, I settled on what I believe to be a better solution.
My last post in this series marked the completion of the vRealize Orchestrator workflow that I use for pre-provisioning tasks, namely generating a unique sequential hostname which complies with a defined naming standard and doesn't conflict with any existing records in vSphere, Active Directory, or DNS. That takes care of many of the "back-end" tasks for a simple deployment.
This post will add in some "front-end" operations, like creating a customized VM request form in Service Broker and dynamically populating a drop-down with a list of networks available at the user-selected deployment site.
While working on my vRealize Automation 8 project, I wanted to let users specify how large a VM's system drive should be and have vRA apply that without any further user intervention. For instance, if the template has a 60GB C: drive and the user specifies that they want it to be 80GB, vRA will embiggen the new VM's VMDK to 80GB and then expand the guest file system to fill up the new free space.
In the same vein as my script to automagically resize a Linux LVM volume to use up free space on a disk, I wanted a way to automatically apply Windows updates for servers deployed by my vRealize Automation environment. I'm only really concerned with Windows Server 2019, which includes the built-in Windows Update Provider PowerShell module. So this could be as simple as Install-WUUpdates -Updates (Start-WUScan) to scan for and install any available updates.
Picking up after Part Two, I now have a pretty handy vRealize Orchestrator workflow to generate unique hostnames according to a defined naming standard. It even checks against the vSphere inventory to validate the uniqueness. Now I'm going to take it a step (or two, rather) further and extend those checks against Active Directory and DNS.
Active Directory Adding an AD endpoint Remember how I used the built-in vSphere plugin to let vRO query my vCenter(s) for VMs with a specific name?
We last left off this series after I'd set up vRA, performed a test deployment off of a minimal cloud template, and then enhanced the simple template to use vRA tags to let the user specify where a VM should be provisioned. But these VMs have kind of dumb names; right now, they're just getting named after the user who requests it + a random couple of digits, courtesy of a simple naming template defined on the project's Provisioning page: I could use this naming template to almost accomplish what I need from a naming solution, but I don't like that the numbers are random rather than an sequence (I want to deploy server001 followed by server002 rather than server343 followed by server718).
I recently shared some details about my little self-contained VMware homelab as well as how I integrated {php}IPAM into vRealize Automation 8 for assigning IPs to deployed VMs. For my next trick, I'll be crafting a flexible Cloud Template and accompanying vRealize Orchestrator workflow that will help to deploy and configure virtual machines based on a vRA user's input. Buckle up, this is going to be A Ride.
Objectives Before getting into the how it would be good to start with the what - what exactly are we hoping to accomplish here?
In a previous post, I described some of the steps I took to stand up a homelab including vRealize Automation (vRA) on an Intel NUC 9. One of my initial goals for that lab was to use it for developing and testing a way for vRA to leverage phpIPAM for static IP assignments. The homelab worked brilliantly for that purpose, and those extra internal networks were a big help when it came to testing.
I recently ran into a peculiar issue after upgrading my vRealize Automation homelab to the new 8.3 release, and the error message displayed in the UI didn't give me a whole lot of information to work with: I connected to the vRA appliance to try to find the relevant log excerpt, but doing so isn't all that straightforward given the containerized nature of the services. So instead I used the vracli log-bundle command to generate a bundle of all relevant logs, and I then transferred the resulting (2.
I picked up an Intel NUC 9 Extreme kit a few months back (thanks, VMware!) and have been slowly tinkering with turning it into an extremely capable self-contained home lab environment. I'm pretty happy with where things sit right now so figured it was about time to start documenting and sharing what I've done.
Hardware (Caution: here be affiliate links)
Intel NUC 9 Extreme (NUC9i9QNX) Crucial 64GB DDR4 SO-DIMM kit (CT2K32G4SFD8266) Intel 665p 1TB NVMe SSD (SSDPEKNW010T9X1) Random 8GB USB thumbdrive I found in a drawer somewhere The NUC runs ESXi 7.
It's a good idea to take a snapshot of your virtual appliances before applying any updates, just in case. When you have multiple vCenter appliances operating in Enhanced Link Mode, though, it's important to make sure that the snapshots are in a consistent state. The vCenter vmdird service is responsible for continuously syncing data between the vCenters within a vSphere Single Sign-On (SSO) domain. Reverting to a snapshot where vmdird's knowledge of the environment dramatically differed from that of the other vCenters could cause significant problems down the road or even result in having to rebuild a vCenter from scratch.
There are a number of fantastic Windows applications for creating bootable USB drives from ISO images - but those don't work on a Chromebook. Fortunately there's an easily-available tool which will do the trick: Google's own Chromebook Recovery Utility app.
Normally that tool is used to creating bootable media to reinstall Chrome OS on a broken Chromebook (hence the name) but it also has the capability to write other arbitrary images as well.
[Update 2021-03-12] This solution recently stopped working for me. While looking for a fix, I found that OpenVPN had published some notes on controlling the official OpenVPN Connect app from Tasker. Jump to the Update below to learn how I adapted my setup with this new knowledge.
I recently shared how I use Tasker and Home Assistant to keep my phone from charging past 80%. Today, I'm going to share the setup I use to automatically connect my phone to a VPN on networks I don't control.
A few months ago, I started using the AccuBattery app to keep a closer eye on how I'd been charging my phones. The app has a handy feature that notifies you once the battery level reaches a certain threshold so you can pull the phone off the charger and extend the lithium battery's service life, and it even offers an estimate for what that impact might be. For instance, right now the app indicates that charging my Pixel 5 from 51% to 100% would cause 0.
Okay, okay, this isn't actually going to be a comparison review between the two wildly-mismatched-but-also-kind-of-similar Chromeblets, but rather a (hopefully) brief summary of my experience moving from an $800 Pixel Slate + $200 Google keyboard to a Lenovo Chromebook Duet I picked up on sale for just $200.
Background Up until last week, I'd been using the Slate as my primary personal computing device for the previous 20 months or so, mainly in laptop mode (as opposed to tablet mode).
I've written in the past about the Linux setup I've been using on my Pixel Slate. My Slate's keyboard stopped working over the weekend, though, and there don't seem to be any replacements (either Google or Brydge) to be found. And then I saw that Walmart had the 64GB Lenovo Chromebook Duet temporarily marked down to a mere $200 - just slightly more than the Slate's keyboard originally cost. So I jumped on that deal, and the little Chromeblet showed up today.
I was pretty excited to get WSL2 and Docker working on my Windows 10 1909 laptop a few weeks ago, but I quickly encountered a problem: WSL2 had no network connectivity when connected to my work VPN.
Well, that's not entirely true; Docker worked just fine, but nothing else could talk to anything outside of the WSL environment. I found a few open issues for this problem in the WSL2 Github with suggested workarounds including modifying Windows registry entries, adjusting the metrics assigned to various virtual network interfaces within Windows, and manually setting DNS servers in /etc/resolv.
Do you (like me) find yourself frequently searching for information within the same websites over and over? Wouldn't it be great if you could just type your query into your browser's address bar (AKA the Chrome Omnibox) and go straight to the results you need? Well you totally can - and probably already are for certain sites which have inserted themselves as search engines.
The basics Point your browser to chrome://settings/searchEngines to see which sites are registered as Custom Search Engines: Each of these search engine entries has three parts: a name ("Search engine"), a Keyword, and a Query URL.
Microsoft's Windows Subsystem for Linux (WSL) 2 was recently updated to bring support for less-bleeding-edge Windows 10 versions (like 1903 and 1909). WSL2 is a big improvement over the first iteration (particularly with better Docker support) so I was really looking forward to getting WSL2 loaded up on my work laptop.
Here's how.
WSL2 Step Zero: Prereqs You'll need Windows 10 1903 build 18362 or newer (on x64). You can check by running ver from a Command Prompt:
I manage a large VMware environment spanning several individual vCenters, and I often need to run PowerCLI queries across the entire environment. I waste valuable seconds running Connect-ViServer and logging in for each and every vCenter I need to talk to. Wouldn't it be great if I could just log into all of them at once?
I can, and here's how I do it.
The Script The following Powershell script will let you define a list of vCenters to be accessed, securely store your credentials for each vCenter, log in to every vCenter with a single command, and also close the connections when they're no longer needed.
I've got an Ender 3 Pro 3D printer, a Raspberry Pi 4, and a Pixel Slate. I can't interface directly with the printer over USB from the Slate (plus having to be physically connected to things is like so lame) so I installed Octoprint on the Raspberry Pi and connected that to the printer's USB interface. This gave me a pretty web interface for controlling the printer - but it's only accessible over the local network.
I found myself with a sudden need for parsing a Linux server's logs to figure out which host(s) had been slamming it with an unexpected burst of traffic. Sure, there are proper log analysis tools out there which would undoubtedly make short work of this but none of those were installed on this hardened system. So this is what I came up with.
Find IP-ish strings This will get you all occurrences of things which look vaguely like IPv4 addresses:
A friend mentioned the BitWarden password manager to me yesterday and I had to confess that I'd never heard of it. I started researching it and was impressed by what I found: it's free, open-source, feature-packed, fully cross-platform (with Windows/Linux/MacOS desktop clients, Android/iOS mobile apps, and browser extensions for Chrome/Firefox/Opera/Safari/Edge/etc), and even offers a self-hosted option.
I wanted to try out the self-hosted setup, and I discovered that the official distribution works beautifully on an n1-standard-1 1-vCPU Google Compute Engine instance - but that would cost me an estimated $25/mo to run after my free Google Cloud Platform trial runs out.