December’s Defiant Sausage

This post went to Patronizers at the beginning of December, and the public at the beginning of January.

The longer I run this thing, the more I regret calling a buck a month “See the Sausage Being Made.” Because it inevitably gets shortened to “sausage,” and that leads nowhere good.

Similarly, I shouldn’t have named that one level “Video Chat.” Obviously, it should have been named “Meet the Rats.”

And my web store should never have used the word “chapbooks.” That’s technically correct, but nobody knows what it means. “Short fiction”–everybody understands that.

Oh well, I’ll have to change all of these in my Copious Free Time. A clear illustration that it’s better to do everything correctly the first time, which means extensive planning, which means never accomplishing anything.

But here we are. Last month of the year, and not dead yet. On to what’s going on.

I contemplated doing a Black Friday sale. This year, the Black Friday sales were more numerous than ever. It was overwhelming, and useless. There is no way to penetrate the noise. If I do a sale, it should be for something like Sysadmin Appreciation Day. Or perhaps for March 24, National Gelato Day. Yes, it’s an Italian holiday, but y’all are global and I respect a people who know how to celebrate the important things in life.

I’ve dragged “Run Your Own Mail Server” up to the rspamd section, where it immediately stopped dead. Work hasn’t stopped, but wordcount has. Rspamd is the right solution and many folks use it, but the documentation is designed for people who already know the tool. It’s gonna take me a bit to pull the software apart and see how it fits together from a sysadmin perspective, rather than the developer’s. Why do I say it’s developer-centric? It’s configured in UCL, Universal Configuration Language. I love UCL. UCL is brilliant. It lets you write configuration files in several different formats, including a plain text format inspired by nginx.

Rspamd’s configuration examples… are in JSON. Sysadmins might know some JSON, we can probably read it, but we don’t routinely write it.

You’re not supposed to edit the configuration files by hand? Fine. But the docs take us through them.

And don’t get me started on redis’ official docs. The first part I stumbled across was well done, which set artificially high expectations for the rest.

It’s not just these projects. The problem is endemic across the entire industry.

I guess that’s why y’all back me. I rage at basic software so you don’t have to. You can save your raging for higher-level software.

Rage is also why I write the orc stories. I got the baseball story I owe the orc Kickstarter backers written. It’ll go to copyedit this week, and then to my backers. Yes, y’all are my backers.

Speaking of stories, my Christmas tale Heart of Coal comes out today. I never knew that my life needed the phrase “tell Santa to stick it up his ho-ho-hole” in my life until I wrote it. Anyway, we’re just short of the Longest Dark when orcs traditionally exchange gifts, like meat and rocks and stuff, so I’m offering it to all my Patronizers. Grab a copy from Bookfunnel. As usual, this is for y’all so please don’t share.

I spent a fair amount of time on BSDCan this month. Sponsorship, the CFP system, and the web site all collided simultaneously. I wound up spending a few days in Dan Langille’s 2004-era PHP to get the site updated for 2024. Dan’s code is fine, for 2004-era PHP. I know perfectly well that the number one rule of completing projects is to do the hard part first, yet I let my committee relax about getting the infrastructure ready. I’ll have updates over at the BSDCan blog in the next couple days. I don’t intend to permanently chair the conference. Dan and I are both getting older, and we need to hand these responsibilities off to folks a few years younger. Plus, I have a whole bunch more books to write. Unfortunately, there are few people in the community who could lead the effort to split Dan into multiple parts. Once that’s complete, anyone who knows how to treat colleagues with respect and negotiate can serve as chair. I’m tempted to say “there’s got to be at least, oh, three folks in the BSD community who could do that” but the truth is, there’s a whole bunch of them.

It’s December, and that means I’ll have the usual all-Patronizer hangout. Everyone’s welcome. This year it’ll be in the evening, at least for me, so hopefully folks who haven’t been able to attend before can. Sorry Europe, gotta mix it up a little. I would like to declare that this was the result of deliberate planning rather than screwing up the morning/evening alternation earlier in the year, but that would be a lie.

I hope to see a bunch of you there. Until next month!

2023 Income Sources

Here’s where my income came from in 2023. (For newcomers, I’ve done these posts for the last few years.)

I’m a writer. My income comes from writing books and making them available. I publish both independently and through publishers. I don’t consult. I don’t seek out speaking fees. I desire to make my living as an author, creating and licensing intellectual property. I make my books available in every channel that offers reasonable terms.

Whenever I share actual dollar figures, people inform me that I can’t possibly be making that much, or that I don’t deserve to make that much, or demand I share “the secret.” The first two are not worth my time, and I’ve been trying to tell everyone the dang secret for years: keep writing, with an attitude of deliberate practice. Nothing productive can come from such discussions, so I don’t say.

How did 2023 look?

My income was flat with 2022 and 2019. While the Great Locked Inside Reading Surge of 2020-2021 supplemented my emergency fund, my income is back at its baseline. I’d like more, sure, but I have achieved Enough. Not bad for a year without many books.

Here’s the detail.

Amazon – 28.87%
Trad Pub – 17.55%
TWP direct sales – 15.29%
TWP sponsorship – 12.00%
TWP patronizer – 7.42%
IngramSpark – 5.54%
Kickstarter – 5.46%
Patreon – 4.56%
Gumroad – 1.53%
Apple – 0.70%
Kobo – 0.50%
Google – 0.37%
Draft2Digital – 0.17%
Aerio – 0.03%
Barnes & Noble – 0.01%

Can I draw any conclusions from this?

My web site (TWP, or Tilted Windmill Press) is again this year’s star. The combination of direct sales, sponsors, and my homebrew Patreon is 34.71% of my income, a couple points over last year. It’s built on Woocommerce with a handful of commercial plugins that total about $600 a year. My business goal is to get folks to buy directly from me rather than retailers, so I’m content but not satisfied.

Amazon is at 28.87%, down a couple points from last year. There’s reasons for that. They don’t have rights to distribute my newest tech book on Kindle. They’ve retaliated by deprioritizing the title in their listings. I’m not crying; I consider Amazon a discovery platform, an entry point to the Reader Acquisition Funnel. I neither love nor hate Amazon. They’re merely a retailer who offers a nonnegotiable take-it-or-leave-it deal. I accept or reject that deal on a case-by-case basis. Losing them as a channel would send me back to the “yellow zone” emergency budget, but we’d survive just fine.

Kickstarter is down, but I only ran campaigns for short story collections. My private Patronizer program grew a point, but that’s a wobble not a trend. Traditional publishing income is up, thanks to a Humble Bundle.

Then there’s the “below two percent” retailers. Gumroad, because they handle VAT for European readers. I want all the readers and Apple, Kobo, and Google serve readers other retailers don’t reach. They’re small, but those nickels spend. Unless things change, this will be the last year I report Barnes & Noble. I spent many happy hours in the 90s and the 00s wandering their aisles and I would like them to be successful for old times’ sake, but they’re just not managing it and their numbers depress me.

Here’s what the last five years have looked like. I have excluded the tiny channels.

It’s hard to call most of these lines “trends.” If you aggregate the various options from my web site, though, you can see a couple things.

Having fewer entities on this graph makes a couple things clear. I dislike that IngramSpark is shrinking year over year. I use IS to fulfill non-Amazon paperback orders and all hardcovers, so this is either an indication that either brick-and-mortar bookstores are struggling, or that I haven’t released a “hit” in a couple years. Which is it?

It also shows that my direct-to-reader business efforts are working. Readers are willing to do business directly with writers. They like supporting individual authors.

What does the swell in trad pub mean? It means that I need multiple sources of income. I have no way to control which business partner will prosper and which will pull a Wile E Coyote. No matter what, I must be able to pay the mortgage.

How much do I make off of sponsorships and Patronizers, as opposed to retailers? Fair question. Let’s see.

After a few years of growth, the non-retail income is down. Sponsorships and Patronizers were up, but Kickstarter was down (again, because I didn’t run a big one). The vital lesson here is:

if I don’t put broadly interesting product in front of people, I don’t get paid.

Now that I’ve shared the secret, it’s time to double-check last year’s expenses. Income is great, but it’s expenses that destroy you.

28: A Griddle Big as the Sky

Declaring the existence of something is a way to make me finish them. Here’s a chunk from the Giant Unnamed Fiction Project.

Weirder, Liberty could see Monterey’s face. Not much. But more than he had all night. A pallid glow from the east outlined Monterey’s angular chin and sharp nose. Distinct shadows filled his deep-set eyes.

A blotch of light marred the eastern sky.

Curiosity tugged Liberty to his feet.

The blotch cast a halo of shooting stars, radiating in all directions.

“Do you hear that?” Dreg said.

Insects buzzed. Something small rustled through the corn.

The fuzzy light was enough to see Monterey’s head shake.

Liberty was about to say no when a high-pitched whistle tickled his ears. More of a warble. Maybe a buzz? No, each second it picked up new notes, new resonances. Fingernails on slate. The grumble of a great engine, like the River Rouge Water Wheel but a thousand times bigger.

The hiss of water dropped on a hot griddle, if the water was the Detroit River and the griddle big as the sky.

Now that you know this thing is half finished, it’ll hopefully push me to get it ready to kickstart before 2025. Doable, barring debacle.

27: Obviously Forged

Here’s another chunk from Run Your Own Mail Server.

Ideally, sysadmins want all the messages from their domain to conform to the highest possible standards. They intend to sign everything with DKIM, and publish SPF records that contain every host that might possibly send mail. Anything that doesn’t have perfect alignment is obviously forged and should be unilaterally discarded. Anyone who’s worked in computing more than a week understands that they missed something, though. Some critical system sends mail from its own hostname rather than the domain, or there’s that weird host system sends mail only when the Galactic Senate starts its decennial session. DMARC deliberately allows a soft deployment. You can publish fierce policies that require strict alignment of SPF and/or DKIM, but ask that failures be reported to you rather than discarded. Use the failure reports to find deployment gaps. Eventually the failure reports will stop coming and you can ask others to quarrantine or even reject noncompliant mails.

The light at the end of this book is clearly visible, and I can even hear the train approaching. Yay!

26: It Can, But Doesn’t

Still hammering on Run Your Own Mail Server.

If you’ve worked with signing protocols like OpenPGP, you’re familiar with digital signatures. You take a chunk of data and sign it. Any alteration to the file invalidates the signature. You might be expecting DKIM to work the same way. It can, but doesn’t.

Traditional mail software has been free to rearrange messages if the programmer thought it necessary or correct. This might include adding or rearranging headers, substituting one kind of whitespace for another, trimming trailing whitespace, transforming line wrapping, and more. Any of these changes invalidate digital signatures. Complicated mail systems might pass messages through multiple MTAs before they reach their destination. Those systems are often from different vendors who each interpret the standards uniquely. Some older so-called “email firewalls” mangled messages to achieve what they branded as “security,” and a few of these systems are still

If you enjoy watching me suffer from cryptography poisoning, you can still sponsor this book or follow the carnage on a few social media platforms.

If you enjoy watching me suffer from cryptography poisoning, you can still sponsor this book or follow me on a few social media platforms.

25: Shoes with Wheels on the Heels

Here’s a snippet from this month’s FreeBSD Journal Letters column.

System administration in a modern enterprise is like performing an oil change on a vehicle doing a hundred and twenty down the freeway. 120 miles an hour, or kilometers, you might ask? When you’re lying on your back on one of those oversized mechanic’s skateboards, clenching the oil wrench in your teeth and wishing you’d worn shoes with wheels on the heels so you wouldn’t have to work quite so hard holding your legs up, it doesn’t matter. Occasionally the driver gets bored with weaving between desktop users guilty of the unspeakable crime of Using The Road While Obeying The Speed Limit Even Though I’m A CEO, so he sideswipes a pothole just to hear your skull bounce off the transmission housing. Wear a helmet. When the oil change is complete, you get to change the spark plugs and flush the coolant. From below, of course. Raising the hood would impair the driver’s vision, and you can’t possibly interfere with the corporate mission, whatever that is.

The .0 release is a metaphorical tire change, that’s all. The trick is to wait until the driver claims there’s a stretch of smooth road ahead and to place the jack snugly between your knees.

No, I’m not cynical about this business. Not at all. This is how it is.

The first three years of this letters column are collected in Letters to ed(1).

24: Little Soft Creatures

Today’s sample is from Fair Balls, a Prohibition Orcs tale that’s going to my backers next week and the rest of the world next April.

The tiny sewn-hide ball settled into the cup of Ivan’s palm.

“Oscar, you see where Mick is?” Brigid said.

How was an orc to remember these human names? Even without coats human children all looked alike, little soft creatures that couldn’t feed themselves until they were twice Ivan’s age.

Brigid pointed. “Behind home plate? You stand there and catch what Ivan throws. Susan! Grab the bat. No, not yet, Oscar! I gotta tell you what to do!”

“I throw,” Ivan said. “Oscar catches.” How could he throw a ball this tiny?

Brigid said, “Look where Susan is. You gotta throw so she can hit it. You want her to miss, but it’s got to be a fair miss, right?”

Fair. A human word that meant orcs lose. And she? Susan was the other woman, so Ivan must not speak to her.

The ball game hadn’t started, and already it made orc balls itch.

Find the earlier Prohibition Orcs tales at my web site. If you get the ebooks from my bookstore, you’ll also receive the exclusive To Serve Orc: Enduring Recipes from the Old Country, Watered Down for America. Yes, they’re real recipes, even if a couple recipes involve difficult-to-obtain ingredients. Everybody loves “Human Porridge”and “Lutesdwarf.”

My Ebook Store Now Offers Gift Cards

Don’t know exactly what you want as a gift for Your Chosen Winter Solstice Holiday, but you know you want it to include my ebooks?

Tilted Windmill Press now offers gift cards. There’s no physical card, mind you. It’s a digital code that gets emailed to the recipient. But if Amazon calls this a ‘gift card’ I can too.

Yes, this is another lame excuse to take your money. Except it’s not your money, it’s money from your friends and family.

You might note that the cards are good for two years, rather than forever. People have expressed interest in TWP gift cards, but I don’t know if that will translate to actual purchases. I am buying the gift card plugin –yes, I could code something myself, but that’s specifically against my guidelines. I’m committing to buying this plugin until at least December 2025. If I decide to stop offering the gift card, I’ll buy the plugin for at least two years afterwards.

While business doesn’t bring me joy, I do find delight in trying things like this. Anything the big guys can do, I can also do. Next year, I’ll be offering some things that the big guys refuse to do. In the meantime, I have to get back to making words.

November’s Noughtwithstanding Sausage

This post went to Patronizers at the beginning of November, and the public in December. A buck a month gets you early access and more.

These posts need titles, so I go for alliteration. Alliteration gives me an excuse to grab my primordial Oxford English Dictionary. I’ve mentioned this before, but I don’t think folks quite appreciate what a font of wordage it is.


It’s ninety years old and smells like knowledge.

Anyway, it’s been quite a month. The Apocalypse Moi Kickstarter is now completely fulfilled. Just as I was writing this sentence, though, the doorbell rang. UPS dropped off two packages, and—yep. It’s two copies of the book, dropshipped from the printer. They were supposed to go to backers. Instead, they went to me. Did I screw up entering the address? Possible. Did the printer screw up? Very possible. Did the printer’s obtuse web-based ordering system refresh inconveniently and overwrite my meticulously hand-entered shipping address with the default address? Screechingly possible. Each has a shipping slip with an order number, so I get to go through the orders and figure out who got shorted.

Or maybe the printer got carried away and shipped me extra books. That happens, too.

If it wasn’t for the lack of conference calls, I’d call this the worst business ever. But then I’d remember working in the auto industry and realize it’s not nearly that bad.

Anyway. That Kickstarter’s over except for the lingering cruft.

I’m to the bit of Run Your Own Mail Server where I get to talk about filtering and greylisting and SPF and all those fun topics. That’s not a huge topic, but it might take me a little longer than I’d like to get through. Which is the story of this book. October was a crunch month for my family. The crunch ends next Monday and I’ll be free to spew words. I’m learning things about email that I didn’t want to know, and details about workarounds that I didn’t want to know. Here’s yesterday.

Postfix’s postscreen(8) performs sanity checks on incoming email connections. Spambots behave badly, taking full advantage of Jon Postel’s original Robustness Principle. Postscreen identifies those bad actors and prevents them from talking to the SMTP server. Seems fine, right?

Postscreen has optional checks that are intrusive. It does most of the SMTP transaction and, if the client behaves well throughout, adds the client’s address to a temporary allowlist. The problem is, it can’t forward that connection to the mail handler. Instead, it gives the client a 400 error to say “I’m sorry, I can’t finish this right now, please come back later.” That’s a normal part of the email protocol. When the client returns, postscreen sees the address on the allowlist and steers it straight to the SMTP server. Simple enough.

Some of you might recognize that as greylisting. Greylisting is a controversial topic that I’m not gonna get into right now, but it is what it is. How does one get email delivered immediately, while still performing sanity checks? In theory, when a mail client can’t deliver to the primary mail server, it should immediately try the backup. Small sites don’t need a backup mail server.

But you can make a faux backup server.

Add a second IP address to your mail server. List it as the backup MX.

The client goes to the primary MX, passes the intrusive tests, and gets the 400 error. It immediately goes to the second MX. That’s the same host, so it has the same temporary allowlist. The mail is immediately accepted. You need to set up the backup MX address so that SMTP connections that arrive there cannot be added to the allowlist, but that’s included in Postfix.

So I go and set this up. I dig through Vultr’s web interface until I find how to get a second IP address and how to add it to a host. I add a second IPv6 address to that test host. Reboot everything, make sure all the connectivity works. Set up Postfix as a faux backup MX, adjust the DNS records. None of this is advanced work, but it’s tedious and annoying and type-prone. But at last everything looks correct, so I go to my other test host and send an email.

The test host tries the IPv4 address, and gets a 400. Good.

The test host tries the IPv6 address. 400. Good.

And then… it stops.

Postfix doesn’t try the backup MX. Why not?

I go to my old mail server, the one that’s running Sendmail. It gets a 400, immediately tries the backup MX, and sails through. Exactly the way it should. I’ll be trying with gmail today, see what they do. While gmail retries delay-queued mail from different IP addresses, I have no idea if the immediate retries change addresses. It’s an interesting test.

But I worked in IT for decades. I know perfectly well that if someone deployed this in the real world and something went wrong with an incoming message, a manager would ask “Are they on the list?” Because that’s what they ask. That meant I had to figure out how to interrogate the allowlist cache. This is not a public Postfix interface, and Postfix’s developer never intended that people should poke at it. I have no problem telling people “this isn’t meant for you, and it might change in the future, and you shouldn’t rely on any of the other data it reveals, but here’s how you glimpse at it.” But that still leaves me figuring out how to grovel through the stupid cache. Turns out you have to specify the cache format on the command line, a hint which appears nowhere in the documentation because you’re not supposed to go poking at the cache.

Anyway.

That’s a day. Forty words written, and I still don’t know why Postfix didn’t immediately try the backup MX.

The fiction crashed to a halt this month, because of aforementioned family crunch. That’ll restart next month. I owe the world an orc baseball story. I’ve figured out how to make that a short story, finally. One of the rules to making a story short is to limit the number of characters, but a baseball team has nine players, so I’d just like to say oops this was a terrible idea.

Ah well. Live and learn. Learn something that will do you absolutely no good in the future, because part of you already knew it.

I’ve taken sponsorships on the mail book, but I’m pondering doing a Kickstarter for it anyway. Sponsors and Patronizers will get theirs, of course, but there’s a broad pool of folks who want a thing to be ready to produce before they buy it. I’m also pondering stretch goals like “for $25k, I will put the book contents on a public web site.” I’d still have the book in stores, of course. But the ebook won’t be available on Kindle. Heck, the way this book is going the ebook might be $19.99. It’s gonna be freaking huge. Anyway, that Kickstarter and such stretch goals is just idle fancy. Some authors have good results with making their books public. For others, it destroys sales.

Which am I?

Only one way to find out, and the test costs only a year’s work.

That’s it for this month. Thanks for Patronizing me. Onward!

23: Bayseian Statistics and Fuzzy Hashes

I would love to finish this book before 2024. It’s not going to happen, but I would love to do it.

Redis is a database, but not in the way PostgreSQL or MySQL or sqlite or hash files or CSV files or Oracle are. While traditional databases prioritize getting data safely ensconced on the disk, Redis treats RAM as its primary data store. Redis has options for safely stashing data on the disk, including options that approach the reliability of traditional databases, but its primary aim is speed. Redis is a key-value store, not an SQL engine; you might think of it as a super-fast network-aware hash file. Almost every operating system has a suitable Redis package.

Rspamd uses Redis for long-term storage of Bayseian statistics and fuzzy hashes, as well as ephemera. It’s best to have a separate Redis instance for each function so that they can be managed appropriately.

You can sponsor this book at my web store. Thank you!