dth by Joshua Wood

Webmentions

How I used 1990s technology to avoid writing JavaScript.

Have you heard of webmentions? They’re similar to pingbacks—but modern—and allow websites to notify each other about different types of activity (like replies on social media). As of 2017, the protocol is a W3C recommendation.

Here’s an example:

When I post a link to this article on Mastodon, Mastodon sends a request back to my website every time someone likes, reposts, or replies to it. I can then display that activity here on my own website (see the bottom of this article). When I post an article here, I can also send webmentions to any websites I mention (link to).

In the case of Mastodon, it’s actually a tad more complicated than that; because Mastodon doesn’t send webmentions natively, there’s a service I use—called Bridgy—to watch Mastodon and send me webmentions on its behalf.

The problem with webmentions and static sites

I wanted to add webmentions to my blog but had a problem. I use a static site generator (Jekyll) to build my website. That means I can’t receive webmentions and process them dynamically without using a 3rd-party service, like Netlify Functions. I want my blog to run forever, though, and I’ve found serverless functions challenging to maintain (Node.js, gross). Also, I’m not an expert on the Webmention protocol and didn’t want to maintain my own implementation.

Fortunately, there is a 3rd-party service specifically for handling webmentions: Webmention.io. Webmention.io is an endpoint for receiving webmentions on your behalf, providing an API that returns well-formatted JSON. There are even plugins for various static site builders, including Jekyll. Most of them query the Webmention.io API at build time and bake in the webmentions for each URL, and/or use client-side JavaScript to grab new webmentions on every page view.


I like my websites to be fast. That’s why I use a static site generator to render plain HTML pages in the first place—servers are much quicker when requesting static pages. I also like the generator to be fast, and querying an API (like Webmention.io) to fetch the webmentions for each page at build time is slow, even with caching. Since Jekyll can render JSON files directly from the file system, I really want to store my webmentions with the rest of my static files and even push them to my git repository for permanent archiving.

Webmention.io can also send Webhooks. Instead of querying an API every time I build my blog, I could listen for incoming webhooks, save the JSON with the rest of my files, and then regenerate the blog (or, better yet, just the mentioned page). For that, I’d still need a dynamic endpoint, but a much simpler one—it just had to authenticate an HTTP POST request and write the JSON data in the request body to disk.

Adding webmentions to this blog

I still didn’t want to use a 3rd-party service to host an HTTP endpoint, and I didn’t want to manage a server process; I wanted a cgi-bin. When I started building websites over 20 years ago, I used Perl and CGI to run simple scripts, like a guestbook (I wrote my own). I prefer Ruby these days—and Perl has deprecated CGI—but could that approach still work? I thought it would be fun to try. It turns out it does work!

By this point, I was full-on coding like it was 1999, and I needed a web server—so obviously, I reached for Apache. Apache still supports mod_cgi, and although deprecated, Perl still supports CGI (and, as a one-time popular legacy system, will probably continue to do so for some time.)

Since I was hosting my blog at Netlify (which cannot run Apache directly), I created a $5/month cloud server at Hetzner. After some basic security hardening, I installed Apache and configured it to serve Jekyll’s _site directory (where it saves the static files). I then added a simple Perl script to Apache’s cgi-bin directory, and after fiddling with file permissions, I had a working endpoint for processing webhooks from Webmention.io.


Here’s how the whole thing works:

  1. Apache serves the static _site directory generated by Jekyll.
  2. When Webmention.io receives a new webmention, it sends a webhook to /cgi-bin/webmention at my website, invoking a process to run my Perl CGI script.
  3. The Perl script authenticates the request; if valid, it saves a new file in Jekyll’s _data directory.
  4. I also run jekyll build --watch on the server, which regenerates the site when the file system changes.
  5. I periodically commit those new files and push them to GitHub for archiving.

That’s it. Now that I had new webmentions saved in my Jekyll project, I could display them using Jekyll’s Liquid templates. You can see all the webmentions for this article below the closing paragraph—and if you like or repost it on Mastodon, Reddit, or Bluesky, you’ll also appear here.


What about monitoring and reliability? My Perl script had a bug when I first tested this, meaning incoming webmentions were lost. Webmention.io doesn’t retry webhooks; even if they do, it’s nice to know when things are failing. For that, I use a product we built at work—Hook Relay. Hook Relay sits between Webmention.io and my site and retries webhooks if my script fails or my site is down. I can also see all of the sent requests, which is handy!

FounderQuest 100

Following a long break (too long!), we’re back in the studio. I give you FounderQuest episode 100 🎙️

FounderQuest is a weekly(ish) podcast from the founders of Honeybadger.

We’re Josh and Ben — two founders with one foot in engineering and the other in business. About ten years ago, we we joined forces with Starr to create an error monitoring product called Honeybadger. The product was very successful, but we decided to stick to our bootstrapping roots and stay tiny. Although Starr has moved on, Josh and Ben continue to share their journey — both the past and the future.

Focus

The best tools in the world won’t help if you lack focus. Attention and practice are all that matter. Make them count.

I started a Mastodon server

This is the 2023 annual update for the journalism-focused Mastodon server that I started on a whim last year. It was originally published at open collective.


It’s been a wild year for social media, with Twitter in turmoil and myriad upstarts competing to be the alternative. I launched federated.press in November 2022 as a refuge for journalists and supporting folks during the largest-ever Twitter exodus—back when X was still Twitter. Since then, we’ve grown to over 2,300 users, with roughly 200-300 active every month. Our members include freelance and independent journalists, congressional correspondents, news organizations, trade unions, and plenty of regular folks like myself. Here’s a recap of our first year.

In January, we joined the Open Collective Foundation, a 501(c)(3) fiscal host. Being sponsored by OCF means we can accept tax-deductible donations—which is important since servers aren’t cheap! (To help us keep the lights on, please become a monthly supporter.) OCF has been an invaluable partner and has saved me a lot of time in administrative work.

In March, we announced a community partnership with a fact-checking project, News Detective. News Detective is part of MIT’s Sandbox Innovation Fund Program, and they’re working with journalism students and the public to promote media literacy. We worked together to test a custom Mastodon integration that integrated federated.press with their fact-checking platform, making it easier to crowdsource fact-checking of content on Mastodon.

Throughout the year, I also struggled with our hosting provider in a futile attempt to keep costs down. Without getting too technical, when we started, we were hosted by Amazon Web Services (AWS), a popular cloud hosting provider. AWS is great for high-availability services (like Mastodon) that need to scale up quickly, and they provide redundancy in case of unexpected failures. That’s great for solo operators like myself, who are working (very) part-time. Unfortunately, AWS is also quite expensive. Early on, it became clear that we needed extra resources to guarantee a reliable service to our users. Still, I was already spending much more than we were bringing in: monthly donations were ~$12/month, but our total operating costs were ~$250/month and growing. As the person who took the initiative to launch federated.press, I was paying the difference (and still am).

Since I was already well over my budget for funding this project, I couldn’t justify adding additional resources; instead, I paid personally by responding to intermittent outages, often during my work days and evenings. I won’t lie—it was stressful. I knew I’d burn out if I didn’t find a more sustainable option. So, I began to research other hosting providers. I didn’t want to be the only person on-call for the server anymore, so I needed to find a managed hosting provider—someone who knew how to run Mastodon.

Enter Jeff Brown of Fourth Estate and Honeytree Technologies. Jeff is a technologist like myself, and in addition to already running Newsie.social (one of the largest news/media Mastodon servers) and recently taking over management of Journa.host (a server for verified journalists), he owns a web services company that offers managed Mastodon hosting. With Jeff’s expertise in technology and journalism and with Mastodon in particular, Honeytree seemed like a good fit for federated.press.

In October, Jeff and I discussed the technical requirements and logistics of migrating federated.press from AWS to a new dedicated server provided by Honeytree. We set a date for the migration—October 13, 2023. I scheduled a few hours of downtime for that day via our status page, and we were all set. When Friday the 13th rolled around (a date that didn’t escape me), Jeff and his team worked to move our database and file storage to the new server. Everything went well, and we were back up within the scheduled maintenance window with a new, faster, cheaper server.

How much cheaper? So far, we’re paying Honeytree roughly half of what we paid AWS and other managed services in September. Our September hosting expenses were $298.79, and we’re paying Honeytree a flat $149/month for a fully-provisioned server. Best of all, performance has been significantly better and more stable since the migration. Thanks, Jeff and team!

That brings us to today, November 3, 2023—one year after I first registered the federated.press domain name. Has it all been worth it? If you’d asked me a few months ago, my answer may have been different, but today it’s yes—definitely worth it. I’ve learned a ton, met some really exciting people, and have had the opportunity to support the journalism community—something that has become increasingly important to me over the past few years. I’m also grateful to our members, especially those who have offered encouragement or contributed financially to help keep federated.press up and running. There is much work to do, but I still believe that ActivityPub and Mastodon are important contributions to the World Wide Web, and I’m glad that we’re a small part of that.

Aggressively part-time

I recently used the phrase “aggressively part-time” to describe the culture and work ethic at Honeybadger. We typically work on Honeybadger for 20-30 hours a week. To get things done, we have to be focused and efficient.

This approach allows us to maximize the time we spend on life outside of work.

I’ve been thinking about applying this concept to the rest of my life. Work is just one area where I desire progress. I want my relationships, interests, and hobbies to improve too.

In family life, I want to become a better partner to my wife and father to my children and to enjoy meaningful experiences together.

I want to expand my knowledge and improve my thinking to grow intellectually and solve problems.

I don’t want to have hobbies—I want to be good at them. I want to develop skill and experience success in each area.

These areas encompass my life goals.

Each area demands focus to improve. But, like work, I can’t pursue everything at once—I need to prioritize.

Aggressively part-time leaves room for your other endeavors—whatever they may be.

A thief in the night

The film that haunted my young dreams.

A photograph of an overturned van in a parking lot. In the background, a sign reads: 'Only Jesus saves from hell' in all caps.

“Are you gonna die?”

“Yes Billy, I am going to die.”

“Are you afraid?”

“Billy, have you ever heard about Jesus?”

The thought haunted me at night. Like Billy was about to do, I’d said the sinner’s prayer as a young child—probably three or four years old—and I’d meant it, too. I didn’t want to go to hell. A few years later, it turned out that going to hell was kid’s stuff. Don’t get me wrong, I still feared the Devil. But now I also feared the guillotine.

The guillotine—that shining death implement from the French Revolution. That chopper of heads. I hadn’t learned about France or the revolution yet, though. I was too young. To me, the guillotine was something to look forward to if you didn’t get taken in the rapture.

Billy was unlucky enough to live during the seven-year period known as the Great Tribulation, after God called the true believers to heaven in an event known as “the rapture.” Following the rapture, the remaining Christians—and those who hadn’t converted—were left to endure God’s wrath on the earth. They would ultimately face the Antichrist, a world ruler who would force humanity to renounce Christ and take the “mark of the beast”—a physical mark on the hand or forehead. Those who refused would be killed. So for Billy, the only path to salvation was a literal, physical death by execution—but only after asking Jesus into his heart.

The story of Billy’s conversion and subsequent death was from a film called Image of the Beast—the third in a four-part film series from the 1970s-80s called A Thief in the Night. The films tell the story of the biblical rapture and tribulation foretold by the book of Revelation. Events unfold on a pretribulationist timeline, where all true Christians are taken bodily into heaven before the tribulation begins—leaving a remnant behind.

A Thief in the Night was my first encounter with apocalyptic Bible prophecy. It was also my first encounter with anti-government conspiracy theories—themes that had already consumed my parents when I was born in the early 1980s. They’d both converted to evangelical Christianity in the decade that saw Nixon resign following the Watergate scandal, the end of the Vietnam War, and the birth of the Religious Right in the wake of the social movements of the 1960s.

For the past decade, my dad had researched and written a newsletter and two books on the Trilateral Commission—a nongovernmental international organization founded by David Rockefeller in 1973. The group’s stated purpose was to foster closer cooperation between the United States and its allies in Asia, Western Europe, and North America. Some people (like my dad) sensed nefarious plans, however. They said that the group was a conspiracy of a globalist elite working across governments to bring about a new world order.

In the first film—titled eponymously, A Thief in the Night—the United Nations uses the crisis following the rapture to establish a one-world government. Those who don’t pledge loyalty to the new government by receiving the Mark of the Beast are quickly arrested, except for those who escape to form a militant underground resistance. A series of escalating conflicts follow, leading to insurgent warfare and the systematic execution of dissidents by the UN-backed government.

The films are poorly made. The goal is not to entertain, but to save souls by scaring the audience into repentance and salvation. For many, the story should seem more silly than terrifying. The fear comes from believing that it’s true—that the same events will soon play out in the real world. Little is left to the imagination; the second film—A Distant Thunder—opens with a message scrolling up the screen like an FBI warning:

The motion picture you are about to experience is fiction. The prophecy is not. The producers of this film are not prophets. They are drawing to your attention what God has said in his own word.

The disclaimer continues:

The film is based upon many references in the books of Daniel and Revelation and upon the following Biblical prophecy:

“For the Lord Himself shall descend from heaven with a shout, with the voice of an archangel, and the dead in Christ shall rise first: then they which are alive and remain shall be caught up together with them in the clouds to meet the lord in the air.” 1 Thessalonians 4:16,17

And from Matthew 24:21:

“For then shall be great tribulation, such as was not since the beginning of the world to this time, no nor ever shall be.”

It still might seem silly to many people, but to a seven or eight-year-old—who has been repeatedly assured by adults of its inevitability—it’s the stuff of nightmares. The intersecting themes of shame, isolation, and physical violence combine to form a cocktail of fear and self-doubt. The fear of being left behind, alone, without your family—the only chance of rejoining them being a violent death and your severed head in a basket on the ground. Dying bravely will prove your worth once and for all.

Death by execution is scary, but the real horror is in the waiting. Waiting for the rapture to see if you’ll be left. Waiting in a jail cell to see if you have the courage to resist taking the mark. Waiting for the chopping block as it cuts down the saints in front of you. Always waiting for the next terrible test of faith.

I’d lie awake in bed, standing in that line of martyrs snaking its way to the execution stage. My family had been taken, and I’d been left behind. I’d prayed the sinner’s prayer before—since I could barely speak—but I wasn’t good enough. I didn’t truly believe. Would I be brave enough to join them now? Would I happily give this life for a new life in eternity, even as every fiber of my being screamed no? And then—after everything—would I finally be accepted, or would I still find myself in hell, tortured for all eternity?

“I’ll pray again, just to be sure.”

Alone, in the dark—I probably gave my life to Christ hundreds of times.

An estimated 300 million people have seen a Thief in the Night. It’s been screened primarily in homes and churches, where the righteous gather the lost to give them the good news: you can avoid all of this—all it costs is your life. In 1995, Tim LaHaye and Jerry B. Jenkins published the first of a new series—Left Behind—which sold so well that it became a multimedia franchise by the mid-2000s.

In Billy’s final moments, David—the only friendly adult he has left—refuses to give information to the UN soldiers to save Billy’s life, knowing he recently prayed the sinner’s prayer:

“Billy, you’re free. They’re gonna take you outside and lay you down. Now you close your eyes, and tell ’em you love Jesus no matter what.”

Turning to the soldiers:

“Now I ask you, what can you do now? The boy’s free. He belongs to Jesus Christ.”

Opinion detox

Feeling overwhelmed? Try an opinion detox.

Opinions are like junk food. They feel good going down but leave you with indigestion and high blood pressure.

Here’s how an opinion detox works:

For 30 days, don’t consume opinions.

Opinions are judgments formed from sources other than facts or knowledge. Common sources of opinion:

  • Social media posts
  • Comments and replies
  • News opinion pages
  • Podcasts
  • Self-help books
  • Magazines
  • Certain friends and relatives1

Like a detox fad diet, it’s not helpful to cut out everything–that’s why this isn’t an information detox.

The goal isn’t to stop thinking; it’s to chill out and start thinking for yourself.

With that in mind, replace those salty, processed, high-fructose opinions with clean, whole sources of information:

  • Books
  • Research papers
  • Academic studies
  • Other well-researched content (essays, articles, podcasts, documentaries, etc.—but not too much! When in doubt, cut it out.)

“But wait, what should I do with my own opinions?”

You’re free to share your opinions, but there’s a problem: people will want to reciprocate. So here’s a better approach: use a notepad. Any notepad will do. Write down your passing thoughts, and let them go.

Once your thoughts have had time to cool, you can shape them into something permanent. Wait to share them until your detox is over.

If you consume too many opinions, try an opinion detox.


  1. If someone immediately comes to mind, they probably qualify.

Make customer support your competitive advantage

Let’s suspend disbelief for a moment, and imagine that you are a customer of my cable company. Your bill just arrived, and it’s $50 more than it should be.

You probably know what happens next: you call my 1-800 number and speak to a very frustrating robot that I purchased to waste your time. Eventually, you get through to a person (not me) who has the power to help you, and after some back-and-forth, you’ll convince them to fix your bill. Afterward, you’ll wonder: why do I put up with this?

I’ll tell you why.

You see, in corporate parlance, the point at which you are frustrated enough to stop being my customer is called your “breakpoint,”1 and—fortunately for me—you didn’t reach it.

Modern customer service employs artificial intelligence to find your breakpoint and allow you to reach that limit but not cross it. At scale, this is much more efficient than ensuring that each customer is individually satisfied.

Isn’t technology grand?

If you run a business, it’s helpful to remember that this is what your customers are dealing with regularly.

Granted, it’s not always such a nightmare scenario. Nowadays, many companies are trying to “personalize” the support experience—but by and large, customer support is a metric to be optimized, and the bar is LOW.

When your competitors view customer support in this way, make it your competitive advantage.

When your next support ticket comes in, ask yourself: how can I surprise this customer with delightful customer support?

If you run a business and aren’t personally handling support, maybe you should be—it’s a great way to talk to your customers.

  1. Everyone Hates Customer Service. This Is Why.

Make Fastmail work like HEY

I’ve been checking out Basecamp’s new email product, HEY. There’s a lot to like about it. HEY collects many email best practices into a simple package. As Basecamp is an opinionated take on project management, HEY is an opinionated take on email.

HEY isn’t perfect, though; its approach seems limited to simple use cases. For instance, I tried forwarding multiple email accounts into it, with mixed results. More advanced features are on the way, but until then I don’t see HEY as a complete alternative to my current email provider: Fastmail.

I use Fastmail to manage all of my email accounts, and it’s great. These are the features that I find particularly useful:

  • Multiple sending identities w/ Gmail integration
  • Personal domain management/DNS hosting
  • Email aliases
  • Filters and rules

You can replicate some of the magic of HEY in Fastmail with the downside being that you must put more effort into setting it up and maintaining it. There are also many more choices available, so it’s important to pick useful patterns (and be alright with “good enough” in other cases).

For me, the best part of HEY is the Screener. Like the telephone, email is better when you screen who you talk to. When someone new emails you for the first time in HEY, their email shows up in the Screener, where you can first decide if you want their emails or not, and what to do with them in the future.

This is how I set up my own screener in Fastmail:

A To Screen folder in Fastmail The end result: new contacts arrive in the To Screen folder, keeping my inbox reserved for people I know.

Create the folder

  1. Navigate to Settings -> Folders
  2. Click Create Folder:
    • Name: To Screen
    • Parent: (None)
    • Color: Green
    • Show in sidebar: Hide if empty
  3. Click Save
  4. Move the new folder right below (or above) the Inbox; you never want to miss a new message.

Create the rule

  1. Navigate to Settings -> Filters & Rules
  2. Click Create Rule:
    • If all of the following conditions apply:
      • Sender is not a contact
  3. Click Continue
  4. Click Create Rule:
    • Move to “To Screen”
  5. Click Save

Screening contacts

New emails will now begin to arrive in the “To Screen” folder, which is visible only as long as there are emails in that folder (you can also hide it when there are no unread emails). To screen a new sender, click into the email and add them to your contacts:

Screening a contact in Fastmail

All future emails from Ben will now arrive in my inbox.

Taking it further

You can add rules so that other actions are performed for some senders–for example, automatically moving receipts to a Receipts folder (like the Paper Trail in HEY). I do a little of that, but the simple screening setup works pretty well for my email process:

  1. Scan the To Screen folder, picking out contacts who should be screened/require action and moving those emails to Inbox
  2. Select all -> Archive
  3. Deal with the remaining emails in Inbox as time permits

This process allows me to spend very little time on email while pretty much always maintaining inbox zero in my To Screen folder.

Finally, I subscribe to a lot of email newsletters (all of them, basically), but I don’t like to read them in my email. I send them to Feedbin instead.

If you want to email me from HEY, you can! My email is josh@joshuawood.net. :grin: