<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/repeating-ourselves-less-with-m4-meax6hzos" -->

---
title: Repeating Ourselves Less with M4 | daily.dev
description: A practical walkthrough of using the POSIX m4 macro processor to reduce repetition in an OpenBSD httpd.conf file. The author explains the difference between...
canonical: https://daily.dev/posts/repeating-ourselves-less-with-m4-meax6hzos
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Repeating Ourselves Less with M4 | daily.dev
og:description: A practical walkthrough of using the POSIX m4 macro processor to reduce repetition in an OpenBSD httpd.conf file. The author explains the difference between...
og:url: https://daily.dev/posts/repeating-ourselves-less-with-m4-meax6hzos
og:image: https://api.daily.dev/og/posts/MeaX6HZOs.png
og:image:alt: Repeating Ourselves Less with M4
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Repeating Ourselves Less with M4

**[Lobsters](https://daily.dev/sources/lobsters)** · 12 min read · 0 upvotes · 0 comments

## Summary

A practical walkthrough of using the POSIX m4 macro processor to reduce repetition in an OpenBSD httpd.conf file. The author explains the difference between AST-based macros (like Lisp) and text-expansion macros (like the C preprocessor and m4), then shows how to define reusable macros for blocking malicious paths, ACME challenge locations, TLS certs, and security headers. A gotcha with m4 treating commas inside macro bodies as argument separators is fixed by swapping commas for a placeholder and running sed afterward. The full annotated config is included, along with a reflection on whether this Unix-philosophy approach is worth it.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://nemin.hu/httpd-macros/index.html>

## Questions this post answers

### Why does m4 mangle my config when I put commas inside a macro definition like hsts {preload, subdomains}?

m4 recursively evaluates macros and treats commas as argument separators everywhere, even inside literal text that isn't meant to be a macro argument list. This causes text after a comma inside a macro body to be silently dropped. The workaround is to temporarily replace commas with a unique placeholder string like ~~ before running m4, then use sed to restore them afterward with a command like sed -i s/~~/,/g.

_developers wrestling with m4 quoting quirks can find writeups like this on daily.dev before rerunning a broken config generation._

### How do I use m4 macros to avoid repeating the same OpenBSD httpd location blocks in every server definition?

Define reusable m4 macros with define(NAME, body) for repeated blocks, such as a BLOCK macro for malicious path matchers, and a BLOCKLIST macro that chains multiple BLOCK calls together. Because m4 macros can reference other macros recursively, you can build up higher-level macros like SERVER, HTTP_REDIRECT, and WWW_REDIRECT that themselves call ACME, TLS, BLOCKLIST, and HEADERS, collapsing an entire multi-site httpd.conf into a few SITE(domain) calls.

_anyone streamlining OpenBSD server configs with macros can track similar sysadmin tricks on daily.dev._

## Community take

How the wider developer community reacted, aggregated from 1 discussion and 16 comments across lobsters (as of 2026-08-31).

**TL;DR:** Reaction is mostly skeptical of m4 itself: people appreciate the puzzle and the Unix-philosophy angle, but many argue m4's escaping and comma-handling quirks make it fragile and not worth the trouble compared to alternatives like Perl, awk, or full config languages.

**Sentiment:** 20% positive · 30% mixed · 50% skeptical

**The case for**

- Some found the piece genuinely fun to read and admired sticking to POSIX tools already present on the base system for long-term self-sufficiency.
- One commenter said they'd steal the idea of using m4 for simple configs even though they'd abandoned it elsewhere.
- Another had success writing a small, working m4 snippet for autoconf-style repetition removal.

**The pushback**

- Several call m4 fundamentally awful/fragile and think it should be retired, saying any quick DIY alternative would be more intuitive.
- The sed-based comma-escaping workaround was seen as brittle, breaking on edge cases like double tildes.
- One commenter recalled m4 causing an infinite loop and eventually abandoning it due to escaping headaches.
- Another noted that m4 code they wrote themselves became unreadable to them just months later.
- Some suggest better-suited tools exist (Perl, awk, Nickel, Guix/Scheme) for this kind of config generation.

**By community**

- lobsters (skeptical): Discussion leans toward viewing m4 as an outdated, fragile tool, with side threads about better alternatives like Guix, Perl, awk, and Nickel.

**Hottest debate:** Whether m4's Unix-philosophy appeal is worth its escaping fragility, versus just using a more robust language or tool.

**Open questions**

- Is there a genuinely better minimal templating tool than m4 for simple config generation without pulling in a full language runtime?
- How would the escaping approach hold up against other edge cases beyond double tildes?

**Highlights**

> M4 is awful and needs to be buried. Macros are useful as a concept, but M4's take has no redeeming qualities. Whatever DIY thing you invent in 5 minutes is likely to be more intuitive and less fragile. Unix has so much crappy stuff that got in 40 years ago on a whim, and we just keep rolling with it because it's already there. The ossified base also makes getting updated tools and libraries cumbersome, perpetuating the problem.
> — [kornel on lobsters · 5 points, 1 comments](https://lobste.rs/s/uueocw/repeating_ourselves_less_with_m4#c_exv21w)

> I once got not too bad with M4. The stuff actually makes sense. I wrote 10 to 15 lines for autoconf and it worked great. It was generating -W option tests for gcc from a list to avoid repetitions. I lookef at the code a few months later and was avsolutely unable to even somewhat parse it. I've never felt so much like a stranger to my own code. I haven't even felt so much like a stranger to other people's perl code! So yeah, you may feel fine using m4 and write readable code. But it's still m4 and you will regret it a few months later.
> — [adrien on lobsters · 2 points](https://lobste.rs/s/uueocw/repeating_ourselves_less_with_m4#c_58fbfo)

> > Solving this is non-trivial. While m4 does have something akin to escaping, it doesn't quite work like it does in other languages and it's brittle enough for me not to even bother with it in this post. >  > Instead, we'll reach for another trusty Unix tool, sed I [ran into a similar issue](https://zakaria.org/posts/2020-08-03-m4) when my blog's custom static site generator was written in shell scripts+M4.   I wrote a post about how I wrote the generator and because I had included snippets of M4 in the post, it put itself into an infinite loop at one point.  I too added some `sed` as a bandaid but I ended up scrapping using M4 because it just became a can of worms in escaping certain stuff... However, using M4 for simple configs here is a pretty fantastic idea I might steal.
> — [zk on lobsters · 2 points](https://lobste.rs/s/uueocw/repeating_ourselves_less_with_m4#c_b3dh3r)

> Yeah, I was full-on agreeing with the article until the escaping mechanism, which pushed it over onto the "I think this is dumb" side again. Now it breaks if someone uses two tildes, which seems very brittle to me.
> — [jeeger on lobsters · 1 points](https://lobste.rs/s/uueocw/repeating_ourselves_less_with_m4#c_yqlv4i)

> Once you're into generating configs and if you don't want to go full nix, there are also great systems that will keep your config data type-checked and well structured, but can generate any final format you want. For example https://nickel-lang.org/ can be serialised to httpd config if you want. And yes, you can still use perl or whatever if you prefer... but we should really just let m4 die already. It's not better than any other system.
> — [viraptor on lobsters · 1 points](https://lobste.rs/s/uueocw/repeating_ourselves_less_with_m4#c_8xgq7e)

**Source threads**

- [lobsters](https://lobste.rs/s/uueocw/repeating_ourselves_less_with_m4) · 20 points · 16 comments

## Similar posts on daily.dev

- [ymawky](https://daily.dev/posts/ymawky-793maq07w) · Lobsters · 1 upvotes · 0 comments
- [Towards Fearless Macros](https://daily.dev/posts/towards-fearless-macros-90opamu2b) · Lobsters · 1 upvotes · 0 comments

---

Tags: [#linux](https://daily.dev/tags/linux), [#openbsd](https://daily.dev/tags/openbsd)

[View this post on daily.dev](https://daily.dev/posts/repeating-ourselves-less-with-m4-meax6hzos)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Repeating Ourselves Less with M4","url":"https://daily.dev/posts/repeating-ourselves-less-with-m4-meax6hzos","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/repeating-ourselves-less-with-m4-meax6hzos"},"datePublished":"2026-08-31T12:34:09.709Z","dateModified":"2026-08-31T16:04:58.933Z","description":"A practical walkthrough of using the POSIX m4 macro processor to reduce repetition in an OpenBSD httpd.conf file. The author explains the difference between...","image":"https://media.daily.dev/image/upload/s--OHB84bZF--/f_auto/v1722860399/public/Placeholder%2010","thumbnailUrl":"https://media.daily.dev/image/upload/s--OHB84bZF--/f_auto/v1722860399/public/Placeholder%2010","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/repeating-ourselves-less-with-m4-meax6hzos","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"linux,openbsd","timeRequired":"PT12M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"Repeating Ourselves Less with M4"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/repeating-ourselves-less-with-m4-meax6hzos#faq","mainEntity":[{"@type":"Question","name":"Why does m4 mangle my config when I put commas inside a macro definition like hsts {preload, subdomains}?","acceptedAnswer":{"@type":"Answer","text":"m4 recursively evaluates macros and treats commas as argument separators everywhere, even inside literal text that isn't meant to be a macro argument list. This causes text after a comma inside a macro body to be silently dropped. The workaround is to temporarily replace commas with a unique placeholder string like ~~ before running m4, then use sed to restore them afterward with a command like sed -i s/~~/,/g. developers wrestling with m4 quoting quirks can find writeups like this on daily.dev before rerunning a broken config generation."}},{"@type":"Question","name":"How do I use m4 macros to avoid repeating the same OpenBSD httpd location blocks in every server definition?","acceptedAnswer":{"@type":"Answer","text":"Define reusable m4 macros with define(NAME, body) for repeated blocks, such as a BLOCK macro for malicious path matchers, and a BLOCKLIST macro that chains multiple BLOCK calls together. Because m4 macros can reference other macros recursively, you can build up higher-level macros like SERVER, HTTP_REDIRECT, and WWW_REDIRECT that themselves call ACME, TLS, BLOCKLIST, and HEADERS, collapsing an entire multi-site httpd.conf into a few SITE(domain) calls. anyone streamlining OpenBSD server configs with macros can track similar sysadmin tricks on daily.dev."}}]}
```

