Speaking about Freezing Saddles at GWU OSCON 2025

On Tuesday, March 25th at 1:40 PM I’m speaking about Freezing Saddles, the DC winter cycling game I help organize and maintain, at George Washington University’s first OSCON (Open Source convention). If you can, register now as pre-registration closes at midnight on Thursday, March 20th (edit: there will be on-site registration available). The abstract of the talk is on the conference site:

You might consider folks who bicycle outdoors in the winter of being obsessive – but the DC area has a unique group of cold-weather cycling enthusiasts who rely on Open Source software to facilitate their Reindeer Games: the Freezing Saddles Winter Cycling competition. Richard Bullington-McGuire did not write the software originally, but 8 years ago he volunteered to take it over from the original author, and has since maintained and extended it with the help of a merry band of volunteer programmers. In this talk Richard will explain the history of the site, the technologies involved including Python and Docker, and how adopting DevOps practices has radically accelerated the evolution of the site. Interested people will get a look at how the site is built and deployed and how they can contribute.

obscure.org turns 30 today

Thirty years ago today I registered the domain name obscure.org. I was eager to run my own Internet services and what emerged is now The Obscure Organization, which is still going strong as a community non-profit. I’m planning on a year of renewal for the organization and reconnecting with both the people involved so far. and the impulses that inspired me to try to share what I learned with the world in a practical way.

I have a lot more to say about this, but for now: Happy 30th birthday to obscure.org!

Streamline Accounting with ledger-pyreport and Docker

I’m pleased to announce the first release (v0.1.4) of a new fork of ledger-pyreport that has Docker support. Fans of the command line accounting software ledger (originally written by my long-time friend John Wiegley) might enjoy this package.

Here it is in action:

(Ledger sample data in report from MIT-licensed rolfschr/GSWL-private)

The original author of this package, Lee Yington Li wrote a lovely blog article ledger-pyreport: Formal accounting reports for ledger-cli that introduced the program; however, they recently archived the original project. One of the commenters on that article asked for Docker support to make it easier to run, as multiple other people had trouble with Python and Flask configuration. I wrote a book on a related topic, Docker for Developers, in 2020 so I thought it would be easy and quick to do this. It took only a few hours to get this new fork with Docker support working, packaged, documented, and published.

Why would I use ledger and ledger-pyreport?

I’ve used other accounting software before (QuickBooks and Quicken), but these tend to be expensive and are both proprietary software. I’ve wanted to try out ledger for years though, but did not have the right project for it, and I was really used to the nice reports that QuickBooks produced.

I’ve been appointed executor of my mother-in-law’s estate, and one of the things you must do is account for inventory, income, and expenses. Tax accountants and state agencies such as the Commissioner of Accounts like to see clear accounting reports, and this package could be a good piece of the puzzle. I am already using ledger-cli to track the inventory, income, and expenses for the estate. I got some extra inspiration from the now-defunct blog article Command Line Probate: Inventory, Part 1: Will It Probate? which gave me more confidence in using plain-text accounting for this

I’ve submitted one round of financial reports generated using ledger-pyreport to the tax accountant helping me and gotten no complaints so far.

New PGP key and a DOS retrocomputing adventure

What should you do when technology has raced by and left you flat-footed? Sometimes a little emulation and a bit of luck can help you escape a legacy trap.

Given the advances in cryptography in the last few years, it was time to generate a new set of PGP keys, and revoke the 2 older keys from 1994 and 1997 that I have had circulating on the Internet. I’d also like to make it a bit easier to reach me in secure ways, so I signed up for Keybase recently. I’m obscurerichard on Keybase.

I had tried to use my 1997-vintage PGP key to sign my Keybase identity, but it complained about the signatures and cryptography when I tried. Furthermore, most of the signatures on the key were done with SHA1, and were more than 20 years old, and vulnerable to spoofing given attacks on SHA1. Given all that I knew I really needed to generate a new PGP key.

I was able to generate the new key with no problems with gpg --full-generate-key on my workstation.

My new GPG key has the ID fingerprint D9B2 B6A6 17A8 8989 918C 3D59 0621 BDC5 DAC3 028E and is on the MIT PGP keyserver, the Ubuntu keyserver, and the OpenPGP keyserver.

Modern practices for PGP dictate generating a key with strong cryptography, such as the Elliptic Curve ed25519 algorithm, and to set the key to expire in 2 years or less. You can reset the expiration date of they key as the date draws near, that helps show you are an active user.

Having generated a new key, I had left three things still to-do:

  1. Signing an attestation of my Keybase identity with the new key,
  2. revoking my old keys generated in 1997 and 1994, and
  3. propagating the revocation to various PGP keyservers.

I was able to generate a revocation for the 2017 key no problem:

gpg --output .gnupg/openpgp-revocs.d/D9B2B6A617A88989918C3D590621BDC5DAC3028E.rev --revoke D9B2B6A617A88989918C3D590621BDC5DAC3028E

I uploaded this revocation, or a fresh export of that public key, to the keyservers. It promptly showed as revoked everywhere.

However, that left an ancient 2014 RSA key that was no longer in my GPG keyring. but I figured I had a backup somewhere. I’m a digital pack rat!

I keep almost everything from past computers around, although sometimes it is in a backup directory or archive file. I found one set of archives that had MS-DOS versions of PGP 2.3 and 2.6, but no private keys, on my household file server. On another backup drive where I have some deep archives of past machines, I found a 1997 archive of an old computer, that had the secring.pgp file that had my 1994 RSA PGP private key.

Modern GPG won’t import that key, so I fired up a fresh Kali box using Vagrant and Virtualbox. This is dead easy! A concise Vagrantfile suitable for running Kali is:

# Kali Vagrantfile
# Copyright (C) 2023 Richard Bullington-McGuire (@obscurerichard)
# MIT-0 Licensed - https://github.com/aws/mit-0
Vagrant.configure("2") do |config|
  config.vm.box = "kalilinux/rolling"

  config.vm.provider "virtualbox" do |vb|
    vb.gui = true
    vb.memory = "4096"
  end

end

I copied the DOS binaries for PGP and the old .pgp directory from the backup in it into the directory where I was running Vagrant, ~/Documents/pgp-dosbox-experiment, so that they would be available in the /vagrant directory on the guest Kali system.

I then installed dosbox on Kali with sudo apt-get update && sudo apt-get install dosbox. I crafted a directory that had the DOS binaries for PGP and the old .pgp directory from the backup in it, and proceeded to revoke the key using the ancient PGP software.

It was a little surreal to be running an almost 30-year old DOS binary on my modern MacBook without any problems. Here’s how it looked:

With the aid of the documentation for PGP 2.6.2, I was able to revoke the key:

Z:\> mount C /vagrant
Drive C is mounted as local directory /vagrant/

Z:\> C:

C:\> DIR
Directory of C:\.
.              <DIR>            19-06-2023 19:08
..             <DIR>            19-06-2023 14:41
HOME           <DIR>            19-06-2023 15:37
PGP23          <DIR>            29-08-2001 17:13
PGP26          <DIR>            19-06-2023 14:53
VAGRAN~1       <DIR>            19-06-2023 14:39
DS_STO~1                  6,148 19-06-2023 15:37
VAGRAN~2                  3,376 19-06-2023 14:39
    2 File(s)             9,524 Bytes.
    6 Dir(s)        262,111,744 Bytes free.

C:\> DIR PGP26\*.EXE

Directory of C:\PGP26\.
PGP      EXE            243,097 22-10-1994 19:37
PI       EXE            144,422 15-01-1996 20:09
    2 File(s)           387,519 Bytes.
    0 Dir(s)        262,111,744 Bytes free.

C:\> SET PATH=Z:\;C:\PGP26

C:\> CD C:\HOME\RBULLING\.PGP

C:\HOME\RBULLING\.PGP\> PGP SECRING.PGP

WARNING: Environmental variable TZ is not defined, so GMT timestamps
may be wrong.  See the PGP User's Guide to properly define TZ
in AUTOEXEC.BAT file.
Pretty Good Privacy(tm) 2.6.2 - Public-key encryption for the masses.
(c) 1990-1994 Philip Zimmermann, Phil's Pretty Good Software. 11 Oct 94
Uses the RSAREF(tm) Toolkit, which is copyright RSA Data Security, Inc.
Distributed by the Massachusetts Institute of Technology.
Export of this software may be restricted by the U.S. government.
Current time: 2023/06/20 01:15 GMT

File contains key(s).  Contents follow...
Key ring: 'SECRING.PGP'
Type bits/keyID    Date       User ID
sec  1024/93862305 1994/09/18 Richard Lunson Bullington III <[email protected]>
                              Richard Lunson Bullington III <[email protected]>
                              Richard Bullington <[email protected]>
                              Richard Bullington <[email protected]>
                              Richard Bullington <[email protected]>
1 matching key found.

Do you want to add this keyfile to keyring 'secring.pgp' (y/N)? y

C:\HOME\RBULLING\.PGP> PGP -KD RBULLING
...
Key for user ID: Richard Lunson Bullington III <[email protected]>
1024-bit key, Key ID 93862305, created 1994/09/18
Key has been revoked.
Also known as: Richard Lunson Bullington III <[email protected]>
Also known as: Richard Bullington <[email protected]>
Also known as: Richard Bullington <[email protected]>
Also known as: Richard Bullington <[email protected]>

Do you want to permanently revoke your public key
by issuing a secret key compromise certificate
for "Richard Lunson Bullington III <[email protected]>" (y/N)?
You need a pass phrase to unlock your RSA secret key.
Key for user ID "Richard Lunson Bullington III <[email protected]>"

Enter pass phrase: Pass phrase is good.  Just a moment....
Key compromise certificate created.

C:\HOME\RBULLING\.PGP> pgp -kxa rbulling revoke.asc
...
Extracting from key ring: 'pubring.pgp', userid "rbulling".

Key for user ID: Richard Lunson Bullington III <[email protected]>
1024-bit key, Key ID 93862305, created 1994/09/18
Key has been revoked.
...
Transport armor file: revoke.asc

Key extracted to file 'revoke.asc'.
 

I was able to upload the public key with the revocation statements to the MIT and Ubuntu keyservers, without any further ado.

Finally, I was ready to sign my Keybase keys with my shiny new PGP key, or so I thought…

$ keybase pgp select
You are selecting a PGP key from your local GnuPG keychain, and
will publish a statement signed with this key to make it part of
your Keybase.io identity.

Note that GnuPG will prompt you to perform this signature.

You can also import the secret key to *local*, *encrypted* Keybase
keyring, enabling decryption and signing with the Keybase client.
To do that, use "--import" flag.

Learn more: keybase pgp help select

#    Algo   Key Id             Created   UserId
=    ====   ======             =======   ======
1    255?   3FD889596619CF98             Richard Lunson Bullington-McGuire <[email protected]>, Richard Lunson Bullington-McGuire <[email protected]>
Choose a key: 1
▶ ERROR key generation error: Unknown signature subpacket: 34 (error 905)

Ugh! Fortunately I found this GitHub bug that had a workaround of disabling the AEAD feature on my key, at least temporarily, to allow interoperability with Keybase:

$ gpg --expert --edit-key 3FD889596619CF98	
(wd: ~/.gnupg)
sec  ed25519/3FD889596619CF98
     created: 2023-06-19  expires: 2025-07-08  usage: SC
     trust: ultimate      validity: ultimate
ssb  cv25519/40D49E83630ADB74
     created: 2023-06-19  expires: 2025-07-08  usage: E
[ultimate] (1). Richard Lunson Bullington-McGuire <[email protected]>
[ultimate] (2)  Richard Lunson Bullington-McGuire <[email protected]>

gpg> showpref
[ultimate] (1). Richard Lunson Bullington-McGuire <[email protected]>
     Cipher: AES256, AES192, AES, 3DES
     AEAD: OCB
     Digest: SHA512, SHA384, SHA256, SHA224, SHA1
     Compression: ZLIB, BZIP2, ZIP, Uncompressed
     Features: MDC, AEAD, Keyserver no-modify
[ultimate] (2)  Richard Lunson Bullington-McGuire <[email protected]>
     Cipher: AES256, AES192, AES, 3DES
     AEAD: OCB
     Digest: SHA512, SHA384, SHA256, SHA224, SHA1
     Compression: ZLIB, BZIP2, ZIP, Uncompressed
     Features: MDC, AEAD, Keyserver no-modify

gpg> setpref AES AES256 CAST5 3DES SHA256 SHA384 SHA512 SHA1 RIPEMD160 ZIP ZLIB AEAD ks-modify
Set preference list to:
     Cipher: AES, AES256, CAST5, 3DES
     AEAD:
     Digest: SHA256, SHA384, SHA512, SHA1, RIPEMD160
     Compression: ZIP, ZLIB, Uncompressed
     Features: MDC
Really update the preferences? (y/N) y
gpg: WARNING: no user ID has been marked as primary.  This command may
              cause a different user ID to become the assumed primary.

sec  ed25519/3FD889596619CF98
     created: 2023-06-19  expires: 2025-07-08  usage: SC
     trust: ultimate      validity: ultimate
ssb  cv25519/40D49E83630ADB74
     created: 2023-06-19  expires: 2025-07-08  usage: E
[ultimate] (1)  Richard Lunson Bullington-McGuire <[email protected]>
[ultimate] (2). Richard Lunson Bullington-McGuire <[email protected]>
gpg> save

Finally I was able to create a signed statement about my Keybase keychain with my new PGP key:

$ keybase pgp select
You are selecting a PGP key from your local GnuPG keychain, and
will publish a statement signed with this key to make it part of
your Keybase.io identity.

Note that GnuPG will prompt you to perform this signature.

You can also import the secret key to *local*, *encrypted* Keybase
keyring, enabling decryption and signing with the Keybase client.
To do that, use "--import" flag.

Learn more: keybase pgp help select

# Algo Key Id Created UserId
= ==== ====== ======= ======
1 255? 3FD889596619CF98 Richard Lunson Bullington-McGuire <[email protected]>, Richard Lunson Bullington-McGuire <[email protected]>
Choose a key: 1
▶ INFO Generated new PGP key:
▶ INFO user: Richard Lunson Bullington-McGuire <[email protected]>
▶ INFO 256-bit EdDSA key, ID 3FD889596619CF98, created 2023-06-19

With this taken care of, I think I’m ready to receive modern encrypted communications via a couple different channels, including PGP and Keybase. I updated my homepage and my email signatures to match my new PGP key. I felt super-accomplished when I revoked those ancient PGP keys, even the 1994-era RSA key that modern software doesn’t really support. Using Vagrant to run Kali for some quick-and-dirty Linux integration turned out to be super-useful.

Reading images created with imageUSB on Windows via Linux

I’ve started to catch up on a set of technology refresh projects in my house related to Linux machines running on small systems, such as the Raspberry Pi family and the ODROID line of systems. As part of this effort, I wanted to make a quick backup of an SD card. I had a Windows 10 system close at hand with a card reader so I found a free utility called imageUSB from Passmark Software that could do the job of making an image backup. However, I found that I initially was not able to read this disk image on a Linux system. This article shows both why this was a problem and two ways to work around that problem.

The SD card was from a system called pi2, a Raspberry Pi 2 that had been running Raspbian based on Debian Stretch and NOOBS. I had already successfully used a fresh SD card to install the latest Raspberry Pi OS on that system and I had done some spot-backups of things like /etc and configuration files from /home/pi but I wanted to have the full boot media available from another Linux system.

When I tried to attach that backup file (pi-2021-02-12.bin) in Linux with the loop device using losetup, it did not see any partitions. I suspected that maybe the partition data was not actually present at the start of the file, so I inspected the file:

root@example:/media/bak/pi2# od -a pi2-2021-02-12.bin  | head
 0000000   i nul   m nul   a nul   g nul   e nul   U nul   S nul   B nul
 0000020 nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul
 0000040 soh nul nul nul enq nul nul nul   k etx nul nul nul nul nul nul
 0000060 nul nul can   5 etx nul nul nul  si   @   %   4  gs soh nul nul
 0000100   3 nul   5 nul   1 nul   E nul   0 nul   4 nul   9 nul   9 nul
 0000120   9 nul   9 nul   E nul   3 nul   D nul   1 nul   9 nul   A nul
 0000140   1 nul   6 nul   D nul   9 nul   6 nul   D nul   C nul   E nul
 0000160   1 nul   D nul   0 nul   5 nul   8 nul   6 nul   B nul   6 nul
 0000200 nul nul   2 nul   F nul   6 nul   8 nul   4 nul   D nul   1 nul
 0000220   B nul   B nul   3 nul   8 nul   9 nul   7 nul   3 nul   2 nul

See the first line of output? It has “imageUSB” interspersed with nul characters. This was a clue that this software left some sort of mark on the file. A quick Google search lead to a discussion on a forum describing how imageUSB  adds a 512 byte header to every start of every image it creates. It looks easy enough to fix with dd though by skipping one 512 byte block when copying it:

root@example:/media/bak/pi2# dd bs=512 skip=1 if=pi2-2021-02-12.bin of=pi2-2021-02-12.img &
[1] 19058
root@example:/media/bak/pi2# ls -l
total 15613848
-rw-r--r-- 1 root     staff         451 Feb 13 15:20 README.md
-rw-rw-r-- 1 user     staff 15931539968 Feb 12 23:18 pi2-2021-02-12.bin
-rw-r--r-- 1 root     staff    41401856 Feb 13 15:21 pi2-2021-02-12.img
-rw-rw-r-- 1 user     staff        1126 Feb 12 22:09 pi2-2021-02-12.log
root@example:/media/bak/pi2# ls -l
total 15654436
-rw-r--r-- 1 root     staff         451 Feb 13 15:20 README.md
-rw-rw-r-- 1 user     staff 15931539968 Feb 12 23:18 pi2-2021-02-12.bin
-rw-r--r-- 1 root     staff    82951680 Feb 13 15:21 pi2-2021-02-12.img
-rw-rw-r-- 1 user     staff        1126 Feb 12 22:09 pi2-2021-02-12.log
root@example:/media/bak/pi2# file pi2-2021-02-12.img
pi2-2021-02-12.img: DOS/MBR boot sector; partition 1 : ID=0xe, start-CHS (0x80,0,1), end-CHS (0x3ff,3,16), startsector 8192, 129024 sectors; partition 2 : ID=0x5, start-CHS (0x3ff,3,16), end-CHS (0x3ff,3,16), startsector 137216, 30979072 sectors

Even better, it’s not really necessary to fix with dd in order to read this file as a Linux loop device as one can simply use the -o or --offset parameter of losetup to skip the imageUSB header:

root@example:/media/bak/pi2# losetup --find --show pi2-2021-02-12.bin -o 512 /dev/loop0 root@example:/media/bak/pi2# sfdisk -l /dev/loop0 Disk /dev/loop0: 14.9 GiB, 15931539456 bytes, 31116288 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xf64b6124 Device        Boot    Start      End  Sectors  Size Id Type/dev/loop0p1           8192   137215   129024   63M  e W95 FAT16 (LBA)/dev/loop0p2         137216 31116287 30979072 14.8G  5 Extended/dev /loop0p5         139264   204797    65534   32M 83 Linux/dev/loop0p6        3604480  3700735    96256   47M  c W95 FAT32 (LBA)/dev/loop0p7        3702784  7614463  3911680  1.9G 83 Linux/dev/loop0p8        7618560  7759871   141312   69M  c W95 FAT32 (LBA)/dev/loop0p9        7766016 20439037 12673022    6G 83 Linux/dev/loop0p10      20439040 24414207  3975168  1.9G 83 Linux/dev/loop0p11      24416256 31115263  6699008  3.2G 83 Linux

This didn’t do it at first though… the loop devices for each partition that I expected to see did not get created. Running partprobe did not work either to find the partitions. I found some advice on forcing losetup to rescan the partition table by appending a -P parameter that worked though.

root@example:/media/bak/pi2# losetup -d /dev/loop0
root@example:/media/bak/pi2# losetup --find --show pi2-2021-02-12.bin -o 512 -P
/dev/loop0
root@example:/media/bak/pi2# lsblk | grep loop
loop0                                       7:0    0  14.9G  0 loop|-loop0p1                                 259:0    0    63M  0 loop|-loop0p2                                 259:1    0     1K  0 loop|-loop0p5                                 259:2    0    32M  0 loop|-loop0p6                                 259:3    0    47M  0 loop|-loop0p7                                 259:4    0   1.9G  0 loop|-loop0p8                                 259:5    0    69M  0 loop|-loop0p9                                 259:6    0     6G  0 loop|-loop0p10                                259:7    0   1.9G  0 loop`-loop0p11                                259:8    0   3.2G  0 loop
root@example:/media/bak/pi2# mount /dev/loop0p10 /mnt/tmp
root@example:/media/bak/pi2# ls -l /mnt/tmp
total 12
drwx------ 2 1000 1000 4096 Jan 11 20:46 ssh-B65YqdJu83g3
drwx------ 2 1000 1000 4096 Jan 11 20:46 ssh-LrQyz3U9EXMx
drwx------ 3 root root 4096 Nov  1 18:17 systemd-private-2379166a348446dab60162396dcdc36f-systemd-timesyncd.service-p0zvYV
root@example:/media/bak/pi2# # that was the tmp directory
root@example:/media/bak/pi2# umount /mnt/tmp
root@example:/media/bak/pi2# mount /dev/loop0p11 /mnt/tmp
root@example:/media/bak/pi2# ls -l /mnt/tmp
total 24
drwx------  8 root root  4096 Feb  7 19:09 docker
drwx------  2 root root 16384 Dec 21  2018 lost+found
drwxr-xr-x 32 1000 1000  4096 Feb  8 00:00 pi
root@example:/media/bak/pi2# # that was the home directory

Although not being able to read this backup file from Linux initially was a bit frustrating to deal with, in fixing it I learned some new tricks regarding Linux loop devices. I hope this is useful to other people who might be facing the same issue.

My first book, Docker for Developers, is out now!

My first book, Docker for Developers from Packt Publishing, is available now on Amazon. I’d like to thank my co-authors Mike Schwartz and Andrew K. Dennis, and my employer, Modus Create, who supported this effort.

I wrote the longest part, Section 2, dealing with deploying Docker applications and monitoring them in production. It has taken over 500 hours of effort to write, edit, record screencasts, and promote the book so far. If you are interested in Docker and want to understand some practical paths to deploy your applications, ranging from very simple single host setups to using a Kubernetes cluster in Amazon Web Services, this book can help you get there.

Monitor your backups, and monitor the monitor that monitors your backups

(Edited on 2019-12-30 to reflect the availability of icinga2-watchdog.sh and to fix minor copy problems related to the timeline and headlines, edited 2020-07-16 to fix links and minor copy problems.)

Learning the hard way about data loss, backups, and monitoring

Once upon a time, I had a really nicely tuned Nagios 1.x monitoring system for The Obscure Organization. It was in production for 7-8 years, from 2009 or maybe 2010 to 2016. It ran on a CentOS 5 host running on the Nexcess VPS service.

I had it tuned that it would only alert if something was broken, it would shut up in the middle of the night, and realistically it could go weeks or months between alert notifications. The systems it was monitoring were very stable, also. I want to emphasize that I had it really, really well tuned – better than any other monitoring system I’ve ever worked with.

Trouble in Monitoring Paradise

But then in the early part of 2016 I got email from Nexcess saying they were shutting down that line of business. They asked me several times if I had migrated away from their service and I said “No!”. At the time I was working on an extremely demanding customer engagement at work and putting in 60+ hour weeks and I could not take the time to migrate this system on their schedule.

I heard nothing from them, but they kept sending bills like clockwork that got paid through a PayPal subscription, so I figured all was well and I still had time.

The only production workload running on that server was the Nagios monitoring system. It monitored all of the Obscure hosts, the services that were running on them, and the Bareos / Bacula backup system jobs that reliably backed up all the servers. It also monitored some odds and ends of information systems I cared about: I’d get a text if my printer ran out of paper.

I’ve had either Bacula or its more libre-focused fork Bareos running in production for Obscure since 2005. I had to use it in anger to restore when Obscure suffered a catastrophic hardware failure in 2008 in the RAID controller on our main server, and it worked flawlessly when it counted. I completed a full restore to a borrowed VM in about 6 hours, almost all of it waiting time for the data to spool off the backup disks. In 2016 I had enough disk space attached to hold 3 months of backups (dailies for a week, differential weeklies for a month, and full monthlies for 3 months).

When I needed to restore something trivial due to operator error in the waning months of 2016, I discovered to my horror that:

  1. The backup system had run out of space and had stopped working several months before due to a low disk space condition, and
  2. the Nagios server had all of its backup files deleted or overwritten months before.

I lost the entire configuration of my finely-tuned monitoring system! 😱😭

Nexcess didn’t have any backups of the decommissioned systems, which seemed kind of reckless. Or maybe their backups rotated out of their storage pools by that point too.

Aftermath and Recovery

In January of 2017 I got Nexcess to refund Obscure more than 6 months of service charges, but that doesn’t really make up for losing the entire Nagios configuration.

In February of 2017 I started building a new Icinga2 server on the a new host that is the only one that Obscure currently runs in AWS EC2, with the intent to replace the old Nagios server.

I had to set the new Icinga2 server aside as I cared for my mother in her last months, she was diagnosed with terminal lung cancer in April of 2017 and died on November 28, 2017.

I didn’t get the new Icinga2 server configured to do anything useful until April of 2019, and I got it to be effectively a superset of what I had in the old Nagios monitor by June of 2019.

Conclusion

You can tune your monitoring system too well! If it is normally silent it can lull you into a false sense of security.

This is why I have Uptime Robot configured as a secondary monitoring system for the Icinga system that replaced the old, now-lost Nagios system. I also have Uptime Robot monitor the most critical hosts and services for Obscure, in case the new primary monitoring system fails. The Uptime Robot free tier is pretty capable, it a good enough job where it counts and sends a non-Obscure email address alerts if things go boom.

I also wrote a watchdog script that runs through cron (icinga2-watchdog.sh) that will tickle me (and the Slack #alerts room where these alerts go) once per day. Between Uptime Robot and the watchdog script, it should be hard to ignore a cascading failure that takes out the monitoring system.

SIC TRANSIT GLORIA MUNDI

A Internet site with staying power – and a trip down FTP memory lane

Digging through an ancient archive of some of my earliest surviving code, I found a file called UCSD.txt, containing a directory listing from a File Transfer Protocol (FTP) site from 26 years ago:

$ ls -l UCSD.TXT
-rwx------  1 rbulling  staff  1612 Mar  6  1993 UCSD.TXT
$ cat !$
cat UCSD.TXT
150 Opening data connection for /bin/ls (128.173.18.252,1033) (0 bytes).
total 5690
-r--r--r--  1 102      ftp        510989 Mar 25  1989 CMT.tar.Z
-r--r--r--  1 ftp      ftp        923933 Jan 20  1991 FINALEdemo.exe
-r--r--r--  1 102      ftp           517 Jan 27  1989 K1patched.note
-r--r--r--  1 102      ftp         53594 Jan 27  1989 K1patched.shar
-r--r--r--  1 ftp      ftp        185801 Jan 20  1991 MPPdemo1.exe
-r--r--r--  1 ftp      ftp        122400 Jan 20  1991 MPPdemo2.exe
-r--r--r--  1 ftp      ftp        343994 Jan 20  1991 MPPdemo3.exe
-r--r--r--  1 ftp      ftp        456064 Feb 15  1992 baldem.exe
-r--r--r--  1 ftp      ftp          1301 Feb 15  1992 baldem.txt
-r--r--r--  1 ftp      ftp            68 Sep  4  1991 byear.doc
-r--r--r--  1 ftp      ftp        130846 Sep  3  1991 byear.zip
-r--r--r--  1 ftp      ftp         12399 Jun  9  1992 camsys10.lzh
-r--r--r--  1 ftp      ftp           114 Jun  9  1992 camsys10.note
-r--r--r--  1 ftp      ftp           735 Jul  3  1992 canvas.txt
-r--r--r--  1 ftp      ftp        205023 Jul  3  1992 canvas.zip
-r--r--r--  1 ftp      ftp         22863 Oct 19  1989 copyist.zip
-r--r--r--  1 ftp      ftp         22554 Oct 21  1989 copyist2.zip
-r--r--r--  1 ftp      ftp         14117 Oct  4  1990 d50get.exe
-r--r--r--  1 ftp      ftp         14563 Oct  4  1990 d50put.exe
-r--r--r--  1 ftp      ftp          1715 Oct  8  1990 d50putget.doc
-r--r--r--  1 ftp      ftp           908 Sep  8  1991 eps.README
-r--r--r--  1 ftp      ftp         61913 Sep  8  1991 eps.tar.Z
-r--r--r--  1 ftp      ftp        307200 Dec 31
$ # Now that's some Internet ancient history!

I found the origin FTP site, ftp.ucsd.edu with a quick Google search by looking for baldem.txt, which seemed like a pretty distinct file name! These files are part of the UCSD MIDI archives, useful to electronic musicians and tinkerers:

Astonishingly, the files that were there in 1993 are still there, along with many newer files. Disappointingly, the timestamps currently present are all fixed to a 2013 date. UCSD has hosted a file transfer server of one sort of another since at least 1973 (see RFC 532, which is being mentioned in RFC 959, the definition of the File Transfer Protocol released in 1985..

Back in the day, before NCSA Mosaic and its many cousins made the World Wide Web popular and easy, when you wanted to find software or files, you first had to identify an FTP site that was a likely source for the type of content you were seeking. Some people kept curated lists of FTP servers in documents on other FTP servers, or in Gopher servers, but there was no universal hyperlinking standard in wide use. You might telnet to an Archie server, find out where the file was, and then use FTP from the command line on your computer to retrieve the file.

These days there are still thousands of FTP servers running that allow public (anonymous) access. The Internet Archive also maintains the FTP Boneyard containing archives of long-gone sites. People are doing some interesting security work surrounding FTP to this day.

Note that FTP lacks cryptographic safeguards for data integrity; an attacker with access to a network node between the client and server can view the clear text of FTP transmissions, and may be able to inject malicious content without being detected. More modern approaches that have cryptographic safeguards against both snooping and data corruption include HTTPS, SFTP and SCP.

The convention for authenticating to a public FTP server is to login with the user anonymous and give your email as the password for politeness. To better compare the 1993 experience to our super-easy-modern-times-2019-web-browser-way, please review this fresh session transcript recorded with a Linux ftp client:

$ ftp ftp.ucsd.edu
Connected to mirror.ucsd.edu.
220 Welcome to mirror.ucsd.edu
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (ftp.ucsd.edu:rbulling): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd midi/software/ibmpc
250 Directory successfully changed.
ftp> dir
227 Entering Passive Mode (132,239,1,12,39,28).
150 Here comes the directory listing.
-r--r--r--    1 ftp      ftp          1281 Jan 09  2013 BANKEDIT.TXT
-r--r--r--    1 ftp      ftp        606423 Jan 09  2013 BANKEDIT.ZIP
-r--r--r--    1 ftp      ftp        510989 Jan 09  2013 CMT.tar.Z
-r--r--r--    1 ftp      ftp        923933 Jan 09  2013 FINALEdemo.exe
-r--r--r--    1 ftp      ftp           517 Jan 09  2013 K1patched.note
-r--r--r--    1 ftp      ftp         53594 Jan 09  2013 K1patched.shar
-r--r--r--    1 ftp      ftp        185801 Jan 09  2013 MPPdemo1.exe
-r--r--r--    1 ftp      ftp        122400 Jan 09  2013 MPPdemo2.exe
-r--r--r--    1 ftp      ftp        343994 Jan 09  2013 MPPdemo3.exe
-r--r--r--    1 ftp      ftp        456064 Jan 09  2013 baldem.exe
-r--r--r--    1 ftp      ftp          1301 Jan 09  2013 baldem.txt
-r--r--r--    1 ftp      ftp            68 Jan 09  2013 byear.doc
-r--r--r--    1 ftp      ftp        130846 Jan 09  2013 byear.zip
-r--r--r--    1 ftp      ftp         12399 Jan 09  2013 camsys10.lzh
-r--r--r--    1 ftp      ftp           114 Jan 09  2013 camsys10.note
-r--r--r--    1 ftp      ftp           989 Jan 09  2013 canvas.txt
-r--r--r--    1 ftp      ftp        213493 Jan 09  2013 canvas.zip
-r--r--r--    1 ftp      ftp        212496 Jan 09  2013 canvas30.exe
-r--r--r--    1 ftp      ftp           919 Jan 09  2013 canvas30.txt
-r--r--r--    1 ftp      ftp         22863 Jan 09  2013 copyist.zip
-r--r--r--    1 ftp      ftp         22554 Jan 09  2013 copyist2.zip
-r--r--r--    1 ftp      ftp         14117 Jan 09  2013 d50get.exe
-r--r--r--    1 ftp      ftp         14563 Jan 09  2013 d50put.exe
-r--r--r--    1 ftp      ftp          1715 Jan 09  2013 d50putget.doc
-r--r--r--    1 ftp      ftp           908 Jan 09  2013 eps.README
-r--r--r--    1 ftp      ftp         61913 Jan 09  2013 eps.tar.Z
-r--r--r--    1 ftp      ftp        307200 Jan 09  2013 fmpaka.exe
-r--r--r--    1 ftp      ftp          1644 Jan 09  2013 fmpaka.not
-r--r--r--    1 ftp      ftp         58175 Jan 09  2013 getit30.arc.uue
-r--r--r--    1 ftp      ftp           318 Jan 09  2013 k1lib.not
-r--r--r--    1 ftp      ftp        130944 Jan 09  2013 k1lib20.zip
-r--r--r--    1 ftp      ftp         97664 Jan 09  2013 k1lib3s.zip
-r--r--r--    1 ftp      ftp           131 Jan 09  2013 k1utl.not
-r--r--r--    1 ftp      ftp         22528 Jan 09  2013 k1utl.zip
-r--r--r--    1 ftp      ftp          1591 Jan 09  2013 k1voice.doc
-r--r--r--    1 ftp      ftp         78208 Jan 09  2013 k1voice.zip
-r--r--r--    1 ftp      ftp           486 Jan 09  2013 k4.txt
-r--r--r--    1 ftp      ftp            92 Jan 09  2013 k4sysop.txt
-r--r--r--    1 ftp      ftp         40094 Jan 09  2013 k4v301.zip
-r--r--r--    1 ftp      ftp          1296 Jan 09  2013 k4v311.txt
-r--r--r--    1 ftp      ftp         80798 Jan 09  2013 k4v311.zip
-r--r--r--    1 ftp      ftp         68736 Jan 09  2013 mbdoc.arc
-r--r--r--    1 ftp      ftp         28928 Jan 09  2013 mbexe.arc
-r--r--r--    1 ftp      ftp          2298 Jan 09  2013 mbnot.txt
-r--r--r--    1 ftp      ftp        179072 Jan 09  2013 mbsrc.arc
-r--r--r--    1 ftp      ftp         15008 Jan 09  2013 mdf23.lzh
-r--r--r--    1 ftp      ftp           307 Jan 09  2013 mdf23.lzh.note
-r--r--r--    1 ftp      ftp           400 Jan 09  2013 midi10.txt
-r--r--r--    1 ftp      ftp         40960 Jan 09  2013 midiex.tar
-r--r--r--    1 ftp      ftp         20470 Jan 09  2013 midix13.arc
-r--r--r--    1 ftp      ftp         72595 Jan 09  2013 mmadp36.arc
-r--r--r--    1 ftp      ftp         19456 Jan 09  2013 mpu401c.arc
-r--r--r--    1 ftp      ftp          6988 Jan 09  2013 mpudemo.c
-r--r--r--    1 ftp      ftp         12512 Jan 09  2013 msa.exe
-r--r--r--    1 ftp      ftp          3138 Jan 09  2013 msa.prn
-r--r--r--    1 ftp      ftp         81473 Jan 09  2013 mt32ed.zip
-r--r--r--    1 ftp      ftp         37755 Jan 09  2013 pc-midi.tar.Z
-r--r--r--    1 ftp      ftp        131517 Jan 09  2013 pkz101.exe
-r--r--r--    1 ftp      ftp         48117 Jan 09  2013 play2.zip
-r--r--r--    1 ftp      ftp        194560 Jan 09  2013 playpak.exe
-r--r--r--    1 ftp      ftp          1743 Jan 09  2013 playpak.not
-r--r--r--    1 ftp      ftp         40005 Jan 09  2013 pmuser.arc
-r--r--r--    1 ftp      ftp           754 Jan 09  2013 procdemo.txt
-r--r--r--    1 ftp      ftp        374451 Jan 09  2013 procdemo.zip
-r--r--r--    1 ftp      ftp        181964 Jan 09  2013 prsmdemo.exe
-r--r--r--    1 ftp      ftp           572 Jan 09  2013 prsmdemo.txt
-r--r--r--    1 ftp      ftp           367 Jan 09  2013 pvicnv10.txt
-r--r--r--    1 ftp      ftp        472877 Jan 09  2013 pvicnv10.zip
-r--r--r--    1 ftp      ftp          2889 Jan 09  2013 qseq-10.txt
-r--r--r--    1 ftp      ftp        126764 Jan 09  2013 qseq-10.zip
-r--r--r--    1 ftp      ftp          5341 Jan 09  2013 sampdemo.txt
-r--r--r--    1 ftp      ftp        981274 Jan 09  2013 sampdemo.zip
-r--r--r--    1 ftp      ftp           677 Jan 09  2013 srbanks.txt
-r--r--r--    1 ftp      ftp        157763 Jan 09  2013 srbanks.zip
-r--r--r--    1 ftp      ftp        140186 Jan 09  2013 sysport-bbs.dir
-r--r--r--    1 ftp      ftp        151476 Jan 09  2013 tabdemo.arc
-r--r--r--    1 ftp      ftp           430 Jan 09  2013 tt.note.to.system.admin
-r--r--r--    1 ftp      ftp           204 Jan 09  2013 tt.txt
-r--r--r--    1 ftp      ftp         83931 Jan 09  2013 tt.zip
-r--r--r--    1 ftp      ftp        186896 Jan 09  2013 txturdem.zip
-r--r--r--    1 ftp      ftp            77 Jan 09  2013 vfxlib.txt
-r--r--r--    1 ftp      ftp         69165 Jan 09  2013 vfxlib.zip
-r--r--r--    1 ftp      ftp         98816 Jan 09  2013 watchx.exe
-r--r--r--    1 ftp      ftp          1740 Jan 09  2013 watchx.not
-r--r--r--    1 ftp      ftp           483 Jan 09  2013 wjmr224.readme
-r--r--r--    1 ftp      ftp        263901 Jan 09  2013 wjmr224.zip
226 Directory send OK.
ftp> quit
221 Goodbye.
$ # ttfn

Succesful laptop repair – Dell Inspiron 7352

I managed to repair my Dell Inspiron 7352 laptop computer again today. This time, the power connector attaching the motherboard to the tip-and-ring barrel connector had come a little loose, and I had to tape it in place. We’ve had 2 Inspiron 7000 class laptops and both have had similar problems.

This touchscreen-convertible, middling-powered machine is pretty good for web browsing, accounting, and lightweight programming and system administration tasks, but it has some warts. This is the 4th time the power connector has failed in some way in either this computer or another one our family owns. The symptoms are either that it doesn’t charge at all, or that complains about not recognizing the power adapter, and that it won’t charge the battery.

The first time this happened I called Dell and wasted the usual hour troubleshooting what was obviously a hardware problem. I sent the failing computer to Dell Service for out-of-warranty repair, they charged almost $200 and it took 3 weeks to get back. Ugh!

The second time it happened I was super frustrated about sending it back to Dell again so I let the computer just be broken for months. The tip shroud inside the barrel connector had broken off. Then the other Inspiron we own broke with similar power problems. This really ticked me off, so I opened up the case and found that one of the wire leads to the barrel connector had separated.

None of the jury rigged fixes I tried was stable so I researched the replacement part, which was easy as the assembly had a part number printed on it. I found a replacement part for less than $10 on Amazon. Thanks, Dell!

Replacing this turned out to be easy and fixed the power problem on both computers. I even ordered one spare just in case this happened again.

This week the symptoms returned on one of the computers, so after jiggling the connector as much as I dared without breaking it to no effect, I opened up the chassis. I then observed that the motherboard connector was not seated firmly, re-seated it, and put a tiny rectangle of Gorilla Tape over it to hold it in place. I didn’t have to use my spare connector.

Earlier this year I had also replaced the internal fan and swapped the magnetic hard drive for a solid state drive. The hard drive was actually failing, was throwing SMART warnings and had 4096 bytes in unreadable sectors. I got to learn how to use ddrescue in the process of fixing it. It’s like getting a whole new machine when upgrades such as this work as expected.

I like having multiples of the same machine because it makes it way easier to troubleshoot and repair the systems. Dell gets both the stinkeye for some bad engineering decisions and kudos for having systems that are easy to repair.